HelloWorld 正则表达式教程

正则表达式是用来描述和匹配文本模式的工具。通过学习字符类、量词、锚点、分组与环视等概念,并结合常见实例(邮箱、手机号、URL、提取替换等),你可以用一套可移植的思路在多种语言和工具中高效处理文本。本文以通俗、一步步带你上手的方式讲解要点、常见陷阱和实战片段,边写边想,带点真实的注解和可立即复用的正则片段。

HelloWorld 正则表达式教程

为什么要学正则表达式

简单说,正则表达式能把“复杂的文本处理变成模式匹配”的工作。你会发现很多重复、琐碎或容易出错的文本任务——比如日志筛选、表单校验、批量替换——用正则都能写得简洁而可靠。当然,学会正则不仅是记住符号,更重要的是学会用“模式思维”去拆解问题。

先把基本概念弄清楚

先像学一门语言那样把基础词汇记住,然后通过例子把它们串起来。

字符与字面量

最直观的就是字面量匹配:abc 就是匹配字符序列 abc。若要匹配元字符(比如点号、星号),需用反斜杠转义:\.\*

常用元字符一览

  • .:匹配除换行外的任意单个字符(取决于模式标志)
  • ^$:行/字符串的起始与结束锚点
  • []:字符类,像 [aeiou] 表示一个元音字符
  • [^]:否定字符类,例如 [^0-9]
  • |:或,像 cat|dog
  • ():分组与捕获
  • \:转义符,用来引用特殊含义或常用字符类(\d、\w、\s 等)

量词:控制重复

量词决定了前面元素出现的次数。

符号 含义 例子
* 0 次或多次(贪婪) ab*c 匹配 ac、abc、abbbc
+ 1 次或多次 ab+c 匹配 abc、abbbc,但不匹配 ac
? 0 次或 1 次 colou?r 匹配 color 和 colour
{n,m} 至少 n 次,至多 m 次 \d{2,4} 匹配 2 到 4 位数字

量词通常是贪婪的(尽量多匹配)。如果想要最小匹配,很多引擎支持懒惰量词,比如 .*?

位置锚点与边界

锚点帮助你限定匹配位置:

  • ^:匹配字符串/行的开始(取决于多行标志 m)
  • $:匹配字符串/行的结束
  • \b:单词边界(字母/数字与非字母/数字之间)
  • \B:非单词边界

这样你可以做更精确的校验,比如以数字开头并以分号结尾的行。

分组、捕获与引用

分组是正则强大的地方。括号不仅把子模式组织在一起,还可以捕获文本以供后续引用或替换。

  • 捕获组:(…)。在替换中常用 $1(JS/许多工具)或 \1(一些工具/引擎)引用第一个捕获组。
  • 非捕获组:(?:…),用于组合而不占用捕获编号。
  • 命名捕获(不同引擎语法不同):常见如 (?P…)(Python)或 (?…)(PCRE/JS 的较新实现)。

回溯引用允许你匹配重复的子串,例如要找到成对的重复单词:\b(\w+)\s+\1\b(大多数引擎中可用)。

环视(Lookaround)——在匹配的同时看左边或右边

环视不会消耗字符,只是对位置进行条件判断。分为前瞻和后顾、正和负两类:

  • 正前瞻:foo(?=bar),匹配 foo,条件是后面紧跟 bar
  • 负前瞻:foo(?!bar),匹配 foo,条件是后面不是 bar
  • 正后顾:(?<=bar)foo,匹配 foo,条件是前面是 bar
  • 负后顾:(?

注意:并非所有引擎都支持变长后顾(如 JS 直到某些版本不支持),所以写跨平台正则时要小心。

实用示例(带思路,不只是正则)

1)邮箱地址(实用且保守的版本)

完全符合 RFC 的邮箱正则会非常复杂,而且在大多数场景不必要。一个平衡可用的常见写法:

^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$

说明:本模式校验常见邮箱格式,限制顶级域名至少 2 个字母。如果你要更严格(比如 IDN、特殊域名),需额外处理或用专业库。

2)手机号(中国大陆常见 11 位)

^1[3-9]\d{9}$

思路:以 1 开头,第二位是 3-9 的某个数字,后续 9 位数字。根据运营商段或国际号码会变,注意不要把校验规则写死在所有场景里。

3)URL(简化版)

URL 有很多变种,下面是一个常见简化版:

^(https?:\/\/)?([A-Za-z0-9-]+\.)+[A-Za-z]{2,}(:\d+)?(\/\S*)?$

说明:可选协议、域名、可选端口和路径。不要用一个正则去做所有 URL 的“真实检查”,更好的方式是用专门的 URL 解析库完成语义检查。

4)提取 HTML 标签内的内容(谨慎使用)

用正则处理复杂或嵌套的 HTML 通常是不可靠的,但针对单一简单标签可以:<([a-z]+)(?:\s[^>]*)?>(.*?)<\/\1>。这能匹配基本的成对标签并捕获内容与标签名。

跨语言与常见工具差异

不同环境对正则的支持、语法或默认行为有差异,几个要点:

  • JavaScript:早期不支持可变长后顾,命名组较新版本才支持,替换字符串中用 $1
  • Python(re):支持 (?P…) 命名组,替换中用 \\1\g。另外有 regex 第三方模块增加了更强功能。
  • Java:使用双反斜杠转义(字符串字面量中),命名组语法类似于 PCRE 的形式但有差异。
  • 命令行工具(grep/sed/awk):语法各异,基本 POSIX 或 PCRE 带来差别,工具间替换语法也不一样(如 sed 用 \1)。

性能与调优小贴士

正则既强大也可能惹性能问题。几个常见经验:

  • 尽量用具体字符而非 .* 盲扫;在能锚定位置时先锚定(用 ^ 或明确前缀)
  • 避免回溯爆炸(catastrophic backtracking):当有重叠的模糊量词组合(如 (a+)+ 或 (.*a){n})时容易产生极端慢速
  • 使用非回溯原子项(某些引擎支持)或占有量词(possessive quantifiers,如 PCRE 的 +*+)降低回溯
  • 在循环或高频场景预编译正则(许多语言支持预编译/缓存模式)

常见错误与调试技巧

我自己常犯的错误也分享下,免得你踩坑:

  • 忘记对斜杠和反斜杠双重转义(尤其在字符串字面量里)
  • 误用贪婪量词导致匹配过多(把 .* 改为 .*? 或更精确的字符集)
  • 混淆捕获组编号和命名组(不同引擎替换语法不同)
  • 在多行文本里忘记设置多行标志或 DOTALL(让 . 匹配换行)

调试工具很有用:把你的正则粘到像 regex101、regexr(工具名)这样的在线测试器上,可以看到分组、渐进匹配和回溯信息(记得不要把隐私数据直接粘到在线工具)。

替换与重排:实战小技巧

替换时要注意目标引擎的引用语法:

  • JavaScript、许多在线工具:替换使用 $1$2
  • 一些工具或语言(如传统 sed/awk):使用 \1 之类

例如,把名字格式从 “姓, 名” 变成 “名 姓”:模式 ^([^,]+),\s*(.+)$,替换用 $2 $1(在 JS 中)。

进阶话题简要触及(以便日后深入)

  • Unicode 与脚本问题:如果处理多语言文本,使用支持 Unicode 类别的引擎(\p{L} 等)会更稳妥。
  • 递归与条件模式:PCRE 等高级引擎支持递归匹配(用于嵌套结构),但跨平台可移植性差。
  • 状态机与实现差异:一些工具用 NFA(回溯)实现,一些使用 DFA(线性时间),这影响性能特性。

一些常用正则片段(便于复制粘贴并理解)

  • 去除字符串首尾空白(大多数语言 trim 用库好,不用正则,但示例):^\s+|\s+$(替换为空串)
  • 只保留数字:\D+(替换为空串)
  • 匹配 0-255 范围的 IPv4 四段之一(片段):(25[0-5]|2[0-4]\d|1?\d{1,2})
  • 匹配 ISO 日期(YYYY-MM-DD)基本形式:^\d{4}-\d{2}-\d{2}$(注意没有语义校验闰年等)

如何系统练习与掌握

学习正则不要只背公式。建议的路径:

  • 先记住基础元字符和简单量词,用真实例子练手(日志、CSV、文本报告)
  • 每次遇到任务,先把目标写成“我想从文本中提取什么”一句话,再拆成小子任务
  • 用测试工具逐步构造正则,观察每一步的匹配结果和分组内容
  • 把复杂任务拆成多个小正则或先用解析器/库完成复杂语义,再用正则做局部清理

写到这里我自己又回想起好多次因为懒用一个 .* 把整个日志吃掉的尴尬瞬间,倒也是好的提醒:学会正则最实用的收益不是记住一个神奇的模式,而是学会用最小的、最清晰的模式去解决问题。接下来你可以挑一两项上面的示例在你的代码/工具里试一遍,边试边改就会更快上手。