人人都会AI编程

15.1 正则语法基础:元字符、量词、分组、断言、字符类

更新时间:2026-07-12

正则表达式(Regular Expression)是一种用单个字符串描述、匹配一系列符合某个句法规则的字符串的模式。在 Python 中,通过 re 模块来使用正则表达式,它是处理文本查找、替换、验证的核心工具。

要写好正则,必须先理解构成模式的几类基本元素:元字符量词字符类分组断言

元字符

元字符是正则中具有特殊含义的字符,就像编程语言里的关键字。如果真想要匹配这些字符本身,需要加反斜杠 \ 转义。

| 元字符 | 含义 | 示例 |
|--------|------|------|
| . | 匹配除换行符外的任意一个字符 | a.b 匹配 "aab", "a1b", "a#b" 等 |
| ^ | 匹配字符串开头 | ^Hello 只匹配以 "Hello" 开头的行 |
| $ | 匹配字符串结尾 | end$ 只匹配以 "end" 结尾的行 |
| | 前一个字符重复0次或多次 | abc 匹配 "ac", "abc", "abbc" |
| + | 前一个字符重复1次或多次 | ab+c 匹配 "abc", "abbc",不匹配 "ac" |
| ? | 前一个字符重复0次或1次 | colou?r 匹配 "color" 和 "colour" |
| \ | 转义字符,使元字符变普通,或表示特殊序列(如 \d) | \. 匹配真正的点号 |
| | | 或运算符,左右表达式任选其一 | cat|dog 匹配 "cat" 或 "dog" |
| () | 分组,见下文分组详解 | (abc)+ 匹配 "abc", "abcabc" |
| [] | 字符类,匹配方括号内的任意字符 | [aeiou] 匹配任意元音字母 |
| {} | 量词,指定重复次数 | a{3} 匹配 "aaa" |

量词

量词用来指定前一个字符或分组的出现次数,它让模式描述“数量”变得简单。

  • ***:零次或多次(贪婪)。等价于 {0,}
  • +:一次或多次(贪婪)。等价于 {1,}
  • ?:零次或一次。等价于 {0,1}
  • {n}:恰好 n 次。
  • {n,}:至少 n 次。
  • {n,m}:至少 n 次,至多 m 次。

贪婪与非贪婪
默认量词都是贪婪的,会尽可能多地匹配字符。如果在量词后加 ?,变为非贪婪(懒惰),尽可能少地匹配。

  • 对于字符串 "<div>内容</div>"
  • "<.*>" 会匹配整个 "<div>内容</div>"(贪婪)。
  • "<.*?>" 会匹配 "<div>""</div>" 分开(非贪婪)。

字符类

字符类用于定义匹配某个位置允许出现的字符集合。写在方括号 [] 中。

  • 直接列举[abc] 匹配 a、b、c 中任意一个。
  • 范围表示[a-z] 匹配任意小写字母,[0-9A-Fa-f] 匹配十六进制数字。
  • 取反[^a-z] 匹配不是小写字母的任意字符(^ 在开头时表示排除)。
  • 预定义字符类(转义序列):
  • \d:数字,等价于 [0-9]
  • \D:非数字
  • \w:单词字符(字母、数字、下划线),等价于 [a-zA-Z0-9_]
  • \W:非单词字符
  • \s:空白字符(空格、制表符、换行等)
  • \S:非空白字符

注意:在 [] 内部,大多数字元字符失去特殊含义,只有 ^(开头取反)、-(范围)、](结束)和 \ 仍需要留意。

分组与捕获

圆括号 () 除了确定运算优先级,还用来捕获匹配的子串

  • 捕获分组(pattern) 会将被匹配的文本存储到一个组中,之后可以通过 re.search() 结果的 .group(编号).group('名称') 获取。
  • 例如,匹配电话号码并提取区号:(\d{3})-(\d{8}),对 "010-12345678" 运行后,.group(1) 得到 010.group(2) 得到 12345678
  • 命名捕获(?P<name>pattern) 给分组起个名字,更清晰。
  • (?P<area>\d{3})-(?P<number>\d{8}),之后用 .group('area') 获取区号。
  • 非捕获分组(?:pattern) 只用于优先级或量词控制,不保存匹配结果,不生成组号,性能更高。
  • (?:http|ftp):// 会匹配协议部分但不单独捕获。
  • 反向引用:在模式里可以用 \1\2 引用前面捕获组匹配到的文本,常用于匹配重复内容。
  • (\w+)\s+\1 匹配连续出现的相同单词,如 "hello hello"。

断言(零宽断言)

断言用于限定当前位置前面或后面必须(或不必须)满足某种条件,但断言本身不消耗字符(零宽度),只做位置检查。

  • 正向先行断言(?=pattern)

要求当前位置之后的字符能匹配 pattern

  • foo(?=bar) 匹配 "foo" 但仅当后面跟着 "bar"("foobar" 中的 foo 匹配,但 "foobaz" 不匹配)。
  • 负向先行断言(?!pattern)

要求当前位置之后的字符不能匹配 pattern

  • foo(?!bar) 匹配后面不是 "bar" 的 "foo"。
  • 正向后顾断言(?<=pattern)

要求当前位置之前的字符能匹配 pattern

  • (?<=\$)\d+ 匹配美元符号后面的数字,如 "$123" 中的 123。
  • 负向后顾断言(?<!pattern)

要求当前位置之前的字符不能匹配 pattern

  • (?<!\$)\d+ 匹配前面不是 $ 的数字。

注意:Python 的 re 模块支持后顾断言,但要求后顾中的模式必须是定长的(不能出现量词如 +*,但可以用 {n} 定长)。不过替代的 regex 第三方库支持变长后顾。

掌握这些基础构件,你就具备了阅读和编写绝大多数正则表达式的核心能力。接下来通过 re 模块的常用方法验证理解,就会越用越顺手。