字面字符与字符类
大多数字符匹配其自身:模式 cat 会找到文本“cat”。有些字符具有特殊含义,例如 . * + ? ( ) [ ] { } ^ $ | \。要按字面匹配其中某个字符,请用反斜杠转义,例如用 \. 匹配句点。
字符类匹配集合中的一个字符。[abc] 匹配 a、b 或 c;[a-z] 匹配一个小写 ASCII 字母;[^0-9] 匹配任何非数字字符。常用的简写有 \d(数字)、\w(字母、数字或下划线)、\s(空白字符),以及它们的反义 \D、\W 和 \S。点 . 匹配除换行以外的任意字符。
在 JavaScript 中,\w 和 \d 只涵盖 ASCII 字符。要匹配任何语言的字母,请配合 u 标志使用 \p{L} 等 Unicode 属性。
量词与锚点
量词指定前一项可以重复的次数:
| 语法 | 含义 | 示例 |
|---|---|---|
* |
0 次或多次 | ab* 匹配 a、ab、abbb |
+ |
1 次或多次 | \d+ 匹配 7 或 2026 |
? |
0 次或 1 次 | colou?r 匹配 color 和 colour |
{n,m} |
n 到 m 次 | \d{2,4} 匹配 2 到 4 位数字 |
锚点匹配的是位置而不是字符。^ 表示输入的开头,$ 表示输入的结尾(使用 m 标志时为每一行的开头和结尾)。\b 是单词边界,因此 \bcat\b 能找到“cat”,但不会匹配“concatenate”。验证整个值时,请锚定两端:^\d{5}$ 只接受恰好五位数字,不接受其他内容。
分组与捕获
圆括号将模式的一部分分组,使量词或选择作用于整组:(ab)+ 重复“ab”,(jpg|png) 匹配两个单词之一。普通分组还会捕获匹配的文本,您可以在替换中以 $1、$2 等形式重复使用。
(?<year>\d{4}) 这样的命名组让模式更易读,并可通过 $<year> 引用。如果只需要分组,可以使用非捕获组 (?:...),避免产生用不到的捕获。LeedyBox 正则表达式测试会列出每个匹配及其捕获组,并预览替换结果。
标志
标志会改变整个模式的行为。常用的 JavaScript 标志有:
g(global):查找所有匹配,而不只是第一个。i(ignore case):将大写和小写视为相同。m(multiline):^和$在每个换行处匹配。s(dotAll):.也匹配换行。u(unicode):启用支持 Unicode 的匹配和\p{...}类。
JavaScript 还有 y(sticky)和 d(匹配索引),测试工具也都支持。
贪婪与惰性,以及灾难性回溯
量词默认是贪婪的:它们尽可能多地匹配,如果模式的其余部分匹配失败,再逐个退还字符。对于文本 <b>bold</b>,模式 <.+> 会匹配整个字符串。加上 ? 会让量词变为惰性,因此 <.+?> 只匹配 <b>。<[^>]+> 这样的否定字符类通常更清晰,也更快。
包括 JavaScript 在内的大多数正则引擎都使用回溯。(a+)+$ 这样的嵌套量词或相互重叠的选择分支,可能会在匹配失败时让引擎尝试海量的组合,从而使页面或服务器卡死。这被称为灾难性回溯;面对不可信的输入时,它可能被用于拒绝服务攻击(ReDoS)。请避免对同一组字符嵌套量词,优先使用具体的字符类而不是 .*,并用不匹配的长输入测试模式。
不同的正则方言
正则表达式没有统一的标准。JavaScript、Python、Java、.NET、PCRE(PHP 所用)、Go 以及各种数据库支持的语法都略有不同。后行断言、占有量词、命名组语法、Unicode 类和替换语法各不相同。例如,Go 的 RE2 引擎不支持环视和反向引用。
LeedyBox 正则表达式测试使用您浏览器的 JavaScript 引擎。在这里可用的模式在其他语言中可能需要修改,因此请在实际运行的环境中再次测试。
常见问题
为什么我的模式只匹配第一处?
没有 g 标志时,JavaScript 在第一个匹配后就会停止。启用 g 即可查找所有匹配。
正则表达式能验证电子邮件地址吗?
正则表达式可以检查一个值看起来是否合理,但无法确认该地址是否存在。通常的验证方法是发送确认邮件。
为什么在多行文本中 ^ 只匹配一次?
默认情况下,^ 和 $ 针对的是整个输入。开启 m 标志后,它们会在每一行的开头和结尾匹配。