正则表达式速查表 — 每个语法元素都有示例

每个正则表达式语法元素都附可运行的示例,标明在 JavaScript、PCRE/PHP、Python、Go、Java 和 .NET 中的支持情况,并提供一键在正则测试工具中试用的链接。

最后核对:2026-10-18 依据ECMAScript 2025(MDN)、PCRE2 10.45、Python 3.14 re、Go 1.27 regexp/syntax、Java 25 Pattern 以及 .NET 正则表达式参考文档核对。来源:MDN regular expressions, PCRE2 pattern syntax, Python re, Go regexp/syntax, Java Pattern, .NET regex quick reference。

共 82 条
正则引擎

✓ 语法相同 · ~ 语法不同或支持有限 · ✗ 不支持。示例在 JavaScript 中运行;备注给出其他语言的写法。

字符与转义

大多数字符匹配其自身。以下十二个字符有特殊含义,要按字面匹配时需加反斜杠:\ ^ $ . | ? * + ( ) [ {(在某些位置,] 和 } 也需要)。

.任意字符#

除换行符外的任意单个字符。加上 s(dotAll)标志后也匹配换行符。

/h.t/g 目标文本 “hat hot h t hit h↵t” 匹配 “hat” “hot” “h t” “hit”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
  • Python re: 只排除 \n;JavaScript 还会排除 \r、\u2028 和 \u2029。
  • Go RE2: 只排除 \n。
\. \$ \(转义元字符#

反斜杠让紧随其后的特殊字符按字面匹配:\. 是真正的点,\$ 是美元符号。

/\$\d+\.\d{2}/g 目标文本 “Total $45.00, tax $3.15, tip 5” 匹配 “$45.00” “$3.15”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
\t \n \r制表符、换行符、回车符#

用名称表示控制字符。Windows 的换行是 \r\n;\r?\n 两种风格都能匹配。

/\w+\t\w+/g 目标文本 “name⇥age↵ana⇥31” 匹配 “name⇥age” “ana⇥31”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
\xhh按十六进制码表示字符#

正好两位十六进制数:\x41 是 A,\x20 是空格。

/\x41/g 目标文本 “A b A” 匹配 “A” “A”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
\uhhhh按 Unicode 码元表示字符#

四位十六进制数,用于基本多文种平面中的字符:\u00e9 是 é。

/\u00e9/g 目标文本 “café résumé” 匹配 “é” “é” “é”
✓ JS 支持✗ PCRE 不支持✓ Py 支持✗ Go 不支持✓ Java 支持✓ .NET 支持
  • PCRE / PHP: 使用 \x{e9}。
  • Go RE2: 使用 \x{e9}。
\u{1F600}任意码位(含辅助平面)#

带花括号的码位写法,emoji 等 U+FFFF 以上的字符需要用它。JavaScript 中需要 u 或 v 标志。

/\u{1F600}/gu 目标文本 “Hi 😀 there 😀” 匹配 “😀” “😀”
✓ JS 支持~ PCRE 语法不同 / 支持有限~ Py 语法不同 / 支持有限~ Go 语法不同 / 支持有限~ Java 语法不同 / 支持有限✗ .NET 不支持
  • PCRE / PHP: 写作 \x{1F600}(PHP 需要 u 修饰符)。
  • Python re: 写作 \U0001F600(八位十六进制数)。
  • Go RE2: 写作 \x{1F600}。
  • Java: 写作 \x{1F600}。
  • .NET: 只支持 \uhhhh;一个 emoji 是两个 UTF-16 码元,例如 \uD83D\uDE00。

字符类

字符类只匹配集合中的一个字符。在 [ ] 内,大多数元字符失去特殊含义;只有 ] \ ^ 和 - 需要注意。

[abc]其中任意一个#

列表中的一个字符。

/gr[ae]y/g 目标文本 “gray grey groy” 匹配 “gray” “grey”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
[^abc]不属于其中任何一个#

不在列表中的一个字符(^ 不在开头时按字面匹配)。也会匹配换行符。

/[^aeiou\s]/g 目标文本 “regex” 匹配 “r” “g” “x”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
[a-z]范围#

两个码位之间的字符。可以组合多个范围:[A-Fa-f0-9] 表示一个十六进制数字。放在开头或末尾的 - 按字面匹配。

/[A-Fa-f0-9]+/g 目标文本 “x: 3fA9 zz” 匹配 “3fA9”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
\d \D数字 / 非数字#

\d 是数字,\D 是其他任意字符。

/\d+/g 目标文本 “Order 66, room 101” 匹配 “66” “101”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
  • Python re: 在 str 模式中 \d 匹配任何 Unicode 数字(如 ٣);只想匹配 0-9 请用 re.ASCII。
  • .NET: 匹配任何 Unicode 数字,除非设置了 RegexOptions.ECMAScript。
\w \W单词字符 / 非单词字符#

字母、数字和下划线。在 JavaScript 和 Go 中仅限 ASCII:\w 不匹配 é。

/\w+/g 目标文本 “snake_case and kebab-case” 匹配 “snake_case” “and” “kebab” “case”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
  • PCRE / PHP: 仅 ASCII,除非使用 PCRE2_UCP(PHP:u 修饰符加 (*UCP))。
  • Python re: 在 str 模式中默认匹配 Unicode 字母和数字。
  • Java: 仅 ASCII,除非开启 U 标志(UNICODE_CHARACTER_CLASS)。
  • .NET: Unicode 字母、数字和连接符标点。
\s \S空白 / 非空白#

空格、制表符、换行符以及(在大多数引擎中)其他 Unicode 空白字符。

/\s+/g 目标文本 “a b⇥c” 匹配 “ ” “⇥”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
  • Go RE2: 仅 ASCII 空白:\t \n \f \r 和空格。
[[:alpha:]]POSIX 方括号字符类#

命名字符类,如 [:alpha:]、[:digit:]、[:space:]、[:punct:],写在方括号内使用。

语法(JavaScript 不支持):[[:alpha:]]+
✗ JS 不支持✓ PCRE 支持✗ Py 不支持✓ Go 支持~ Java 语法不同 / 支持有限✗ .NET 不支持
  • JavaScript: 使用 [A-Za-z],或加 u 标志使用 \p{L}。
  • Java: 使用 \p{Alpha}、\p{Digit}、\p{Punct}。
[\p{L}--[a-z]]字符类差集 / 交集#

字符类内部的集合运算。JavaScript 需要 v 标志(ES2024):-- 表示差集,&& 表示交集。

/[\p{L}--[a-z]]+/gv 目标文本 “abcÉtéXYZ” 匹配 “É” “éXYZ”
✓ JS 支持~ PCRE 语法不同 / 支持有限✗ Py 不支持✗ Go 不支持~ Java 语法不同 / 支持有限~ .NET 语法不同 / 支持有限
  • PCRE / PHP: 仅 PCRE2 10.45+,使用 (?[ … ]) 扩展字符类语法。
  • Java: 交集 [a-z&&[^aeiou]];差集写成与取反字符类的交集。
  • .NET: 差集 [a-z-[aeiou]];不支持交集。

锚点与边界

锚点匹配的是位置而不是字符,因此不会消耗文本。

^ $字符串开头 / 结尾(加 m 时为行)#

不加 m 标志时,^ 和 $ 表示整个输入的开头和结尾;加上后表示每一行的开头和结尾。

/^\w+/gm 目标文本 “first line↵second line” 匹配 “first” “second”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
  • PCRE / PHP: $ 也能匹配末尾 \n 之前的位置。
  • Python re: $ 也能匹配末尾 \n 之前的位置。
  • Java: $ 也能匹配末尾行终止符之前的位置。
  • .NET: $ 也能匹配末尾 \n 之前的位置。
\b单词边界#

单词字符与非单词字符之间(或输入的边缘)。用于匹配完整单词。

/\bcat\b/g 目标文本 “cat concat cats cat.” 匹配 “cat” “cat”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
  • JavaScript: 仅识别 ASCII 单词字符,即使加了 u 标志也一样。
  • Go RE2: 仅识别 ASCII 单词字符。
\B非单词边界#

位于单词内部,例如只在 "cat" 是更长单词的一部分时匹配。

/\Bcat/g 目标文本 “concat cat bobcat” 匹配 “cat” “cat”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
\A \z \Z绝对开头 / 结尾#

无论是否为多行模式,都表示输入的开头和结尾。\Z 还允许末尾有一个换行符(Python 除外,在 Python 中它等同于 \z)。

语法(JavaScript 不支持):\A\d+\z
✗ JS 不支持✓ PCRE 支持~ Py 语法不同 / 支持有限~ Go 语法不同 / 支持有限✓ Java 支持✓ .NET 支持
  • JavaScript: 不加 m 标志使用 ^ 和 $。
  • Python re: \A 和 \z(3.14+);\Z 表示绝对结尾,相当于其他引擎的 \z。
  • Go RE2: \A 和 \z;没有 \Z。
\G上一次匹配的结尾#

上一次匹配结束的位置;用于匹配连续的片段。

语法(JavaScript 不支持):\G\d
~ JS 语法不同 / 支持有限✓ PCRE 支持✗ Py 不支持✗ Go 不支持✓ Java 支持✓ .NET 支持
  • JavaScript: 没有 \G;y(sticky)标志可实现同样的“必须从这里开始”效果。

量词:贪婪、懒惰、占有

量词重复它前面的元素。贪婪模式(默认)先尽可能多地匹配再回退;懒惰模式(加 ?)尽可能少地匹配;占有模式(加 +)从不回退。

*零次或多次#

重复 0 次到无限次。

/ba*/g 目标文本 “b ba baaa” 匹配 “b” “ba” “baaa”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
+一次或多次#

重复 1 次到无限次。

/lo+l/g 目标文本 “lol loool ll” 匹配 “lol” “loool”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
?可选#

零次或一次。

/colou?r/g 目标文本 “color colour colouur” 匹配 “color” “colour”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
{n}正好 n 次#

正好重复 n 次。

/\d{3}/g 目标文本 “12 345 6789” 匹配 “345” “678”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
{n,}n 次或更多#

至少重复 n 次。

/\d{2,}/g 目标文本 “1 22 333” 匹配 “22” “333”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
{n,m}n 到 m 次#

重复 n 到 m 次,尽可能多。

/\d{2,3}/g 目标文本 “1 22 4444” 匹配 “22” “444”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
  • Go RE2: 超过 1000 的次数会被拒绝。
{,m}最多 m 次#

重复 0 到 m 次。只有部分引擎支持;其他引擎会当作字面文本 "{,m}" 或报错。{0,m} 则在所有引擎中都有效。

语法(JavaScript 不支持):\d{,3}
✗ JS 不支持~ PCRE 语法不同 / 支持有限✓ Py 支持✗ Go 不支持✗ Java 不支持✗ .NET 不支持
  • JavaScript: 不加 u 时是字面文本,加 u 时是语法错误;请写 {0,3}。
  • PCRE / PHP: 仅 PCRE2 10.43+。
  • Go RE2: 请写 {0,3}。
  • Java: 请写 {0,3}。
  • .NET: 被当作字面文本;请写 {0,3}。
.* .+贪婪(默认)#

先取尽可能长的匹配,再逐个退还字符,直到剩余部分能够匹配。这里它把两个标签都吞了进去。

/<.+>/g 目标文本 “<b>bold</b>” 匹配 “<b>bold</b>”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
*? +? ?? {n,m}?懒惰(非贪婪)#

取尽可能短的匹配。表达式“匹配过多”时,这通常就是解决办法。

/<.+?>/g 目标文本 “<b>bold</b>” 匹配 “<b>” “</b>”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
  • Go RE2: 也可以用 U 标志,它会互换贪婪和懒惰模式。
*+ ++ ?+占有#

不回溯的贪婪模式:一旦匹配,字符永远不会退还。失败得更快,也能防止灾难性回溯。

语法(JavaScript 不支持):"[^"]*+"
✗ JS 不支持✓ PCRE 支持~ Py 语法不同 / 支持有限✗ Go 不支持✓ Java 支持✗ .NET 不支持
  • JavaScript: 不支持占有量词和原子组;可用 (?=(…))\1 模拟。
  • Python re: Python 3.11+。
  • Go RE2: 不需要:RE2 从不回溯。
  • .NET: 使用原子组 (?>…)。

分组与反向引用

圆括号把元素组合起来,供量词和多选使用,并且(除非标记为非捕获)保存匹配到的内容。

( … )捕获组#

分组并捕获;按左括号出现的顺序从 1 开始编号。

/(\d{3})-(\d{4})/g 目标文本 “Call 555-0199 or 555-0123” 匹配 “555-0199” “555-0123”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
(?: … )非捕获组#

只分组不保存,组号保持稳定,匹配开销也略小。

/(?:ab)+/g 目标文本 “ababab ab a” 匹配 “ababab” “ab”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
(?<name> … )命名分组#

以名称捕获,之后可按名称读取(JavaScript 中为 match.groups.name)。

/(?<year>\d{4})-(?<month>\d{2})/g 目标文本 “Released 2026-10” 匹配 “2026-10”
✓ JS 支持✓ PCRE 支持~ Py 语法不同 / 支持有限✓ Go 支持✓ Java 支持✓ .NET 支持
  • PCRE / PHP: 也支持 (?'name'…) 和 (?P<name>…)。
  • Python re: 只支持 (?P<name>…)。
  • Go RE2: (?P<name>…);从 Go 1.22 起也接受 (?<name>…)。
  • .NET: 也支持 (?'name'…)。
\1按编号反向引用#

匹配与之前某个分组捕获内容相同的文本。

/(\w)\1/g 目标文本 “bookkeeper” 匹配 “oo” “kk” “ee”
✓ JS 支持✓ PCRE 支持✓ Py 支持✗ Go 不支持✓ Java 支持✓ .NET 支持
  • Go RE2: RE2 没有反向引用(否则会破坏其线性时间保证)。
\k<name>按名称反向引用#

与 \1 相同,但使用名称。示例匹配成对引号中的文本。

/(?<q>['"]).*?\k<q>/g 目标文本 “say "hi" or 'yo'” 匹配 “"hi"” “'yo'”
✓ JS 支持✓ PCRE 支持~ Py 语法不同 / 支持有限✗ Go 不支持✓ Java 支持✓ .NET 支持
  • PCRE / PHP: 也支持 \k{name}、\g{name} 和 (?P=name)。
  • Python re: 写作 (?P=name)。
a|b多选(或)#

匹配任意一边。备选项从左到右依次尝试,所以当一个是另一个的前缀时,把较长的放在前面。

/cat|dog/g 目标文本 “hotdog catalog” 匹配 “dog” “cat”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
(?> … )原子组#

分组一旦匹配成功,引擎就不会再回溯进去。

语法(JavaScript 不支持):(?>a|ab)c
✗ JS 不支持✓ PCRE 支持~ Py 语法不同 / 支持有限✗ Go 不支持✓ Java 支持✓ .NET 支持
  • Python re: Python 3.11+。
  • Go RE2: 不需要:RE2 从不回溯。
(?i) (?i: … )内联标志#

在表达式内部开启或关闭标志。(?i) 作用于表达式剩余部分;(?i:…) 只作用于该分组;(?-i:…) 关闭标志。

/(?i:hello) world/g 目标文本 “HELLO world HELLO WORLD” 匹配 “HELLO world”
~ JS 语法不同 / 支持有限✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
  • JavaScript: 只支持限定范围的 (?i:…) / (?-i:…) 写法,适用于 i、m 和 s(ES2025)。开头的 (?i) 是语法错误。
  • Python re: 全局 (?i) 必须位于表达式的最开头(从 3.11 起放在其他位置会报错);(?i:…) 可放在任意位置。
(?(1)yes|no)条件匹配#

如果第 1 组参与了匹配,则匹配 "yes",否则匹配 "no"。

语法(JavaScript 不支持):(<)?\w+(?(1)>)
✗ JS 不支持✓ PCRE 支持✓ Py 支持✗ Go 不支持✗ Java 不支持✓ .NET 支持
(?R) (?1)递归 / 子程序调用#

重新进入整个表达式或某个分组,用于匹配嵌套结构,例如成对的括号。

语法(JavaScript 不支持):\((?:[^()]|(?R))*\)
✗ JS 不支持✓ PCRE 支持✗ Py 不支持✗ Go 不支持✗ Java 不支持~ .NET 语法不同 / 支持有限
  • Python re: 第三方 regex 模块支持。
  • .NET: 不支持递归;用平衡组 (?<open-close>…) 处理嵌套。
(?# … )内联注释#

引擎会忽略它。较长的注释请使用 x(扩展)标志。

语法(JavaScript 不支持):\d{3}(?#area code)
✗ JS 不支持✓ PCRE 支持✓ Py 支持✗ Go 不支持✗ Java 不支持✓ .NET 支持

前瞻与后顾

环视检查当前位置旁边的内容,但不把它包含在匹配结果中。它们和锚点一样是零宽度的。

(?= … )正向前瞻#

后面紧跟着 …(不包含在匹配结果中)。

/\d+(?=px)/g 目标文本 “10px 20em 30px” 匹配 “10” “30”
✓ JS 支持✓ PCRE 支持✓ Py 支持✗ Go 不支持✓ Java 支持✓ .NET 支持
  • Go RE2: RE2 不支持任何形式的环视。
(?! … )负向前瞻#

后面不是 …。其中的 \d 可防止引擎为了让检查通过而退还数字。

/\d+(?!px|\d)/g 目标文本 “10px 20em” 匹配 “20”
✓ JS 支持✓ PCRE 支持✓ Py 支持✗ Go 不支持✓ Java 支持✓ .NET 支持
(?<= … )正向后顾#

前面是 …(不包含在匹配结果中)。

/(?<=\$)\d+(?:\.\d\d)?/g 目标文本 “Cost: $42.50 or 42” 匹配 “42.50”
✓ JS 支持~ PCRE 语法不同 / 支持有限~ Py 语法不同 / 支持有限✗ Go 不支持~ Java 语法不同 / 支持有限✓ .NET 支持
  • JavaScript: 任意长度(ES2018)。
  • PCRE / PHP: 每个备选项的长度都必须有上限;从 PCRE2 10.43 起支持可变长度(默认最多 255)。
  • Python re: 仅支持固定宽度:(?<=ab|cd) 可以,(?<=a+) 会报错。
  • Java: 仅支持有上限的长度:内部不能有 * 或 +。
  • .NET: 任意长度。
(?<! … )负向后顾#

前面不是 …。

/(?<!\$)\b\d+\b/g 目标文本 “$30 and 45” 匹配 “45”
✓ JS 支持~ PCRE 语法不同 / 支持有限~ Py 语法不同 / 支持有限✗ Go 不支持~ Java 语法不同 / 支持有限✓ .NET 支持
  • PCRE / PHP: 长度规则与正向后顾相同。
  • Python re: 仅支持固定宽度。
  • Java: 仅支持有上限的长度。
\K重置匹配起点#

把目前为止匹配到的内容从结果中丢弃;相当于没有长度限制的后顾。

语法(JavaScript 不支持):price: \K\d+
✗ JS 不支持✓ PCRE 支持✗ Py 不支持✗ Go 不支持✗ Java 不支持✗ .NET 不支持
  • JavaScript: 使用 (?<=…) 或捕获组。

标志(修饰符)

JavaScript 把标志写在结尾斜杠之后(/x/gi)。其他语言则传入常量(re.I、Pattern.CASE_INSENSITIVE、RegexOptions.IgnoreCase)或使用内联 (?i)。

g全局(所有匹配)#

查找所有匹配,而不是找到第一个就停止。matchAll 和 replaceAll 必须使用它。

/o/g 目标文本 “foo boo” 匹配 “o” “o” “o” “o”
✓ JS 支持~ PCRE 语法不同 / 支持有限~ Py 语法不同 / 支持有限~ Go 语法不同 / 支持有限~ Java 语法不同 / 支持有限~ .NET 语法不同 / 支持有限
  • PCRE / PHP: 没有该标志:使用 preg_match_all() / preg_replace()。
  • Python re: 没有该标志:使用 re.findall()、re.finditer()、re.sub()。
  • Go RE2: 没有该标志:使用 FindAll… 系列方法。
  • Java: 没有该标志:用 matcher.find() 循环。
  • .NET: 没有该标志:使用 Regex.Matches()。
i忽略大小写#

不区分大小写匹配。

/hello/gi 目标文本 “Hello HELLO hello” 匹配 “Hello” “HELLO” “hello”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
  • Python re: re.I / re.IGNORECASE 或 (?i)。
  • Java: CASE_INSENSITIVE(除非加 UNICODE_CASE,否则仅限 ASCII)或 (?i)。
  • .NET: RegexOptions.IgnoreCase 或 (?i)。
m多行#

^ 和 $ 匹配每行的开头和结尾,而不只是输入的两端。

/^-\s.+$/gm 目标文本 “- one↵- two↵three” 匹配 “- one” “- two”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
  • Python re: re.M / re.MULTILINE。
  • .NET: RegexOptions.Multiline。
s点号匹配换行#

让 . 也匹配换行符。不加该标志时,可移植的“任意字符”写法是 [\s\S]。

/<p>.*?</p>/gs 目标文本 “<p>a↵b</p>” 匹配 “<p>a↵b</p>”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
  • Python re: re.S / re.DOTALL。
  • Java: Pattern.DOTALL。
  • .NET: 名为 RegexOptions.Singleline。
x扩展(自由空白)#

忽略表达式中的空白,# 开始注释,长表达式可以分多行排版。

语法(JavaScript 不支持):(?x) \d{3} - \d{4} # local number
✗ JS 不支持✓ PCRE 支持✓ Py 支持✗ Go 不支持✓ Java 支持✓ .NET 支持
  • Python re: re.X / re.VERBOSE。
  • Java: Pattern.COMMENTS。
  • .NET: RegexOptions.IgnorePatternWhitespace。
uUnicode#

按码位处理输入(因此 . 能匹配一个完整的 emoji),启用 \p{…} 和 \u{…},并让无效转义报错。

/^.$/gu 目标文本 “😀” 匹配 “😀”
✓ JS 支持~ PCRE 语法不同 / 支持有限~ Py 语法不同 / 支持有限~ Go 语法不同 / 支持有限~ Java 语法不同 / 支持有限~ .NET 语法不同 / 支持有限
  • PCRE / PHP: PHP 的 u 修饰符(UTF-8 模式);加 (*UCP) 让 \w 和 \d 支持 Unicode。
  • Python re: 无需标志:str 模式本身就是 Unicode;用 re.ASCII 可关闭。
  • Go RE2: 没有该标志:Go 始终按 UTF-8 码位处理。
  • Java: UNICODE_CASE 和 UNICODE_CHARACTER_CLASS(U)。
  • .NET: 没有该标志:始终按 UTF-16 码元处理(一个 emoji 占两个)。
vUnicode 集合#

ES2024 对 u 的升级:字符类集合运算(--、&&)、嵌套字符类以及 \p{RGI_Emoji} 等字符串属性。不能与 u 同时使用。

/[\p{L}&&\p{ASCII}]+/gv 目标文本 “Ünïcode text” 匹配 “n” “code” “text”
✓ JS 支持✗ PCRE 不支持✗ Py 不支持✗ Go 不支持✗ Java 不支持✗ .NET 不支持
y粘连(sticky)#

每次匹配都必须从上一次结束的位置(lastIndex)开始。适合编写词法分析器。

/\d/gy 目标文本 “12a3” 匹配 “1” “2”
✓ JS 支持~ PCRE 语法不同 / 支持有限~ Py 语法不同 / 支持有限✗ Go 不支持~ Java 语法不同 / 支持有限~ .NET 语法不同 / 支持有限
  • PCRE / PHP: 使用 \G。
  • Python re: 使用 pattern.match(text, pos)。
  • Java: 使用 \G 或 matcher.lookingAt()。
  • .NET: 使用 \G。
d匹配索引#

添加 match.indices,包含每个捕获组的起止位置(ES2022)。

语法(JavaScript 不支持):/(?<y>\d{4})/d
✓ JS 支持~ PCRE 语法不同 / 支持有限~ Py 语法不同 / 支持有限~ Go 语法不同 / 支持有限~ Java 语法不同 / 支持有限~ .NET 语法不同 / 支持有限
  • PCRE / PHP: 始终可获取偏移量(PREG_OFFSET_CAPTURE)。
  • Python re: 始终可用:m.span(n)。
  • Go RE2: 始终可用:FindStringSubmatchIndex。
  • Java: 始终可用:matcher.start(n) / end(n)。
  • .NET: 始终可用:Group.Index / Length。

Unicode 属性 \p{…}

属性转义按 Unicode 类别或文字系统匹配字符,这是跨语言匹配“任意字母”唯一可靠的方法。在 JavaScript 中需要 u 或 v 标志。

\p{L}任意字母#

所有文字系统中的字母:é、ß、東、д。

/\p{L}+/gu 目标文本 “naïve café 東京 123” 匹配 “naïve” “café” “東京”
✓ JS 支持✓ PCRE 支持✗ Py 不支持✓ Go 支持✓ Java 支持✓ .NET 支持
  • PCRE / PHP: PHP 处理 UTF-8 输入时需要 u 修饰符。
  • Python re: 使用第三方 regex 模块,或用 [^\W\d_] 表示“字母”。
\p{Lu} \p{Ll}大写 / 小写字母#

通用类别:Lu 大写字母、Ll 小写字母、N 数字、P 标点、S 符号、Z 分隔符。

/\p{Lu}/gu 目标文本 “Élan Vital” 匹配 “É” “V”
✓ JS 支持✓ PCRE 支持✗ Py 不支持✓ Go 支持✓ Java 支持✓ .NET 支持
\P{…}不具有该属性#

大写 P 表示取反:\P{L} 表示任何非字母字符。

/\P{L}+/gu 目标文本 “abc-123” 匹配 “-123”
✓ JS 支持✓ PCRE 支持✗ Py 不支持✓ Go 支持✓ Java 支持✓ .NET 支持
\pL单字母简写#

单字母类别可省略花括号。

语法(JavaScript 不支持):\pL+
✗ JS 不支持✓ PCRE 支持✗ Py 不支持✓ Go 支持✓ Java 支持✗ .NET 不支持
  • JavaScript: 必须加花括号:\p{L}。
  • .NET: 必须加花括号:\p{L}。
\p{Script=Greek}文字系统#

某一种文字系统的字符。sc= 是简写;Script_Extensions(scx=)还包括多个文字系统共用的字符。

/\p{Script=Greek}+/gu 目标文本 “alpha α, beta β” 匹配 “α” “β”
✓ JS 支持~ PCRE 语法不同 / 支持有限✗ Py 不支持~ Go 语法不同 / 支持有限✓ Java 支持✗ .NET 不支持
  • PCRE / PHP: \p{Greek}、\p{sc:Greek} 或 \p{scx:Greek}。
  • Go RE2: \p{Greek}。
  • Java: 写作 \p{script=Greek}、\p{sc=Greek} 或 \p{IsGreek}。
  • .NET: 只支持 \p{IsGreek} 这类命名区块(是码位范围,而非文字系统)。
\p{sc=Han}汉字(中文 / 日文)#

汉字表意文字。要匹配日文假名,再加上 \p{sc=Hiragana} 和 \p{sc=Katakana}。

/\p{sc=Han}+/gu 目标文本 “Tokyo 東京 2026 中文” 匹配 “東京” “中文”
✓ JS 支持~ PCRE 语法不同 / 支持有限✗ Py 不支持~ Go 语法不同 / 支持有限✓ Java 支持~ .NET 语法不同 / 支持有限
  • PCRE / PHP: \p{Han}。
  • Python re: 使用 [\u4e00-\u9fff] 这样的范围(只覆盖基本区块)。
  • Go RE2: \p{Han}。
  • Java: 也可用 \p{IsHan}。
  • .NET: 只支持区块,例如 \p{IsCJKUnifiedIdeographs}。
\p{RGI_Emoji}Emoji(完整序列)#

加 v 标志时,可匹配完整的 emoji,包括肤色和家庭组合序列。加 u 时,\p{Extended_Pictographic} 只匹配单个图形字符。

/\p{RGI_Emoji}/gv 目标文本 “Go 👍🏽 team 👨‍👩‍👧!” 匹配 “👍🏽” “👨‍👩‍👧”
✓ JS 支持~ PCRE 语法不同 / 支持有限✗ Py 不支持✗ Go 不支持~ Java 语法不同 / 支持有限✗ .NET 不支持
  • PCRE / PHP: 较新的 PCRE2(10.40+)可通过布尔属性匹配单个码位;没有序列属性。
  • Java: \p{IsEmoji} 匹配单个码位(Java 21+)。
\X字素簇#

用户感知上的一个字符,例如 e 加组合重音符,或一个国旗 emoji。

语法(JavaScript 不支持):\X
✗ JS 不支持✓ PCRE 支持✗ Py 不支持✗ Go 不支持✓ Java 支持✗ .NET 不支持
  • JavaScript: 用 Intl.Segmenter 按字素拆分。
  • Python re: regex 模块支持。

替换语法

替换字符串中该怎么写。这是各语言差异最大的地方,所以你所用语言那一栏比 JavaScript 示例更重要。

$&整个匹配#

插入匹配到的全部文本。

/\d+/g 目标文本 “3 apples, 12 pears” 替换为 “[$&]” → “[3] apples, [12] pears”
✓ JS 支持~ PCRE 语法不同 / 支持有限~ Py 语法不同 / 支持有限~ Go 语法不同 / 支持有限~ Java 语法不同 / 支持有限✓ .NET 支持
  • PCRE / PHP: preg_replace 中用 $0 或 \0。
  • Python re: \g<0>。
  • Go RE2: ${0} 或 $0(Expand / ReplaceAllString)。
  • Java: $0.
  • .NET: 也可用 $0。
$1编号分组#

插入第 1 组捕获的内容。交换两个单词:

/(\w+)\s(\w+)/g 目标文本 “hello world” 替换为 “$2 $1” → “world hello”
✓ JS 支持✓ PCRE 支持~ Py 语法不同 / 支持有限✓ Go 支持✓ Java 支持✓ .NET 支持
  • PCRE / PHP: 也可用 \1 和 ${1}。
  • Python re: \1 或 \g<1>(使用原始字符串 r"\1")。
  • Go RE2: 后面紧跟字母或数字时用 ${1}x,否则 Go 会把 $1x 当作名为 "1x" 的分组。
$<name>命名分组#

插入命名分组的内容。把 ISO 日期改写成 日/月/年:

/(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/g 目标文本 “2026-10-18” 替换为 “$<d>/$<m>/$<y>” → “18/10/2026”
✓ JS 支持✗ PCRE 不支持~ Py 语法不同 / 支持有限~ Go 语法不同 / 支持有限~ Java 语法不同 / 支持有限~ .NET 语法不同 / 支持有限
  • PCRE / PHP: preg_replace 不支持命名引用;请使用组号或 preg_replace_callback()。
  • Python re: \g<name>。
  • Go RE2: ${name}(或 $name)。
  • Java: ${name}。
  • .NET: ${name}。
$$字面美元符号#

在替换字符串中转义 $。

/(\d+)/g 目标文本 “Price: 20” 替换为 “$$$1” → “Price: $20”
✓ JS 支持~ PCRE 语法不同 / 支持有限~ Py 语法不同 / 支持有限✓ Go 支持~ Java 语法不同 / 支持有限✓ .NET 支持
  • PCRE / PHP: 后面不是数字或 { 的 $ 本来就是字面字符;在它之后引用分组请写 ${1}。
  • Python re: $ 没有特殊含义;反斜杠要转义为 \\。
  • Java: \$(Matcher.quoteReplacement() 可转义整个字符串)。
$` $'匹配之前 / 之后的文本#

插入输入中位于匹配之前或之后的内容。很少用到,但偶尔很方便。

/=/ 目标文本 “key=value” 替换为 “ is set ($') and was ($`) ” → “key is set (value) and was (key) value”
✓ JS 支持✗ PCRE 不支持✗ Py 不支持✗ Go 不支持✗ Java 不支持✓ .NET 支持

常用表达式(附真实局限)

大家搜索最多的表达式,写得易读,并且不会出现灾难性回溯。每条都说明了它做不到什么。

Email (practical)查找类似邮箱的字符串#

本地部分、@,以及至少含一个点的域名。

/[\w.+-]+@[\w-]+(?:\.[\w-]+)+/g 目标文本 “Write to ana.lee+news@example.co.uk or bob@test.dev.” 匹配 “ana.lee+news@example.co.uk” “bob@test.dev”

注意: 会拒绝合法但少见的地址(带引号的本地部分、非 ASCII 域名),也会接受一些无效地址(a..b@x.y)。任何正则都无法判断邮箱是否真实存在:请发送确认邮件。

✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
URL查找文本中的 http(s) 链接#

遇到空白、引号和尖括号时停止,并去掉末尾的句号、逗号等标点。

/https?://[^\s<>"]*[^\s<>".,;:!?)]/g 目标文本 “See https://example.com/a?b=1, or (http://test.dev/x).” 匹配 “https://example.com/a?b=1” “http://test.dev/x”

注意: 适合把文本中的网址转成链接,不适合做校验。要检查 URL,请使用所用语言的 URL 解析器(JavaScript 中为 new URL()),再检查协议和主机。

✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
IPv4 address四段 0–255 的数字#

每段限定在 0–255,且不带前导零。

/\b(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}\b/g 目标文本 “10.0.0.1 256.1.1.1 192.168.1.254” 匹配 “10.0.0.1” “192.168.1.254”

注意: 不支持 IPv6、CIDR 后缀或端口。校验时请使用 IP 解析器(Python ipaddress、Go net/netip、Node net.isIP)。

✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
Date YYYY-MM-DDISO 8601 日期#

月份 01–12,日期 01–31。

/\b\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])\b/g 目标文本 “2026-10-18, 2026-13-01, 2026-02-31” 匹配 “2026-10-18” “2026-02-31”

注意: 只检查格式:2026-02-31 也能通过。要排除不存在的日期,请用日期库解析。

✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
Date MM/DD/YYYY美式日期#

一位或两位的月和日,四位的年。

/\b(?:0?[1-9]|1[0-2])/(?:0?[1-9]|[12]\d|3[01])/\d{4}\b/g 目标文本 “Due 10/18/2026 or 1/5/2027, not 13/01/2026” 匹配 “10/18/2026” “1/5/2027”

注意: 01/02/2026 在美国是 1 月 2 日,在其他大多数地方是 2 月 1 日;正则无法知道本意是哪个。

✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
Phone (North America)(416) 555-0199 及其变体#

十位数字,可带括号、空格、点或短横线。

/\(?\b\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b/g 目标文本 “(416) 555-0199, 416.555.0199, 4165550199” 匹配 “(416) 555-0199” “416.555.0199” “4165550199”

注意: 仅适用于北美号码。国际号码请使用 libphonenumber 等库;并以 E.164 格式存储号码(见下一行)。

✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
Phone (E.164)国际格式 +CC…#

加号、不以 0 开头的国家代码,总共最多 15 位数字。

/^\+[1-9]\d{1,14}$/gm 目标文本 “+14165550199↵+447911123456↵0044791112” 匹配 “+14165550199” “+447911123456”

注意: 只检查 E.164 格式,不检查号码是否已分配,也不检查长度是否符合所在国家的规定。

✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
Hex colour#rgb、#rgba、#rrggbb、#rrggbbaa#

CSS 接受的四种长度。

/#(?:[\da-fA-F]{8}|[\da-fA-F]{6}|[\da-fA-F]{3,4})\b/g 目标文本 “#fff #244b3f #12345 #ff000080 #1234567” 匹配 “#fff” “#244b3f” “#ff000080”

注意: 也会匹配较长文本中的内容,例如带 #片段 的 URL;要校验单个值,请用 ^…$ 锚定。

✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
URL sluglowercase-words-with-hyphens#

小写字母和数字,用单个连字符分隔。

/^[a-z0-9]+(?:-[a-z0-9]+)*$/gm 目标文本 “my-post-2026↵My Post↵-bad-↵good” 匹配 “my-post-2026” “good”

注意: 仅限 ASCII。要根据标题生成 slug,请使用 URL slug 生成器,而不是正则。

✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
Trim whitespace首尾空格#

替换为空字符串。不加 m 标志时,^ 和 $ 表示整个文本的两端。

/^\s+|\s+$/g 目标文本 “ padded text ” 替换为 “” → “padded text”

注意: 所有现代语言都有内置的 trim(),更快也更清晰;只在无法调用代码的地方(编辑器、配置文件)使用正则。

✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
Collapse spaces连续空格合并为一个#

把两个或更多空格或制表符替换为一个空格。

/[ \t]{2,}/g 目标文本 “too many ⇥ spaces” 替换为 “ ” → “too many spaces”
✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
Duplicate wordsthe the、is is#

紧跟着自身的单词。加 i 后,"The the" 也能被找出来。

/\b(\w+)\s+\1\b/gi 目标文本 “This is is a test test of The the editor” 匹配 “is is” “test test” “The the”

注意: 需要反向引用,所以在 Go 中不可用。"had had" 和 "that that" 有时是正确的英语。

✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
Password rules小写、大写、数字,12 位以上#

每个前瞻从开头检查一条规则;.{12,} 设定长度。

/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{12,}$/gm 目标文本 “short1A↵alllowercase123↵GoodPassword42” 匹配 “GoodPassword42”

注意: NIST SP 800-63B 不建议设置字符组合规则:应要求足够长度,并对照已泄露密码列表进行检查。

✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
UUID8-4-4-4-12 位十六进制#

版本 1–8,带 RFC 9562 变体位。

/\b[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\b/gi 目标文本 “id 3f2b8c1e-9d4a-4b7e-8f6a-1c2d3e4f5a6b and 00000000-0000-0000-0000-000000000000” 匹配 “3f2b8c1e-9d4a-4b7e-8f6a-1c2d3e4f5a6b”

注意: 会拒绝 nil UUID(全为 0)和 max UUID(全为 f),而它们是合法的特殊值。

✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持
Strip HTML tags删除 <标签>#

替换为空字符串,得到粗略的纯文本。

/<[^>]+>/g 目标文本 “<p>Hello <b>world</b></p>” 替换为 “” → “Hello world”

注意: 遇到属性、注释和脚本中的 > 会出错,也不会解码 &amp; 等实体。切勿用它净化不可信的 HTML;请使用 DOMParser 或 DOMPurify 等净化库。

✓ JS 支持✓ PCRE 支持✓ Py 支持✓ Go 支持✓ Java 支持✓ .NET 支持

这是一份静态参考:搜索和筛选都在浏览器中进行,“试用”链接会打开我们的浏览器端正则表达式测试工具。 浏览全部免费工具.

发现问题,或者觉得哪里可以更好?每条消息我们都会阅读,并尽快修复。

这份正则表达式速查表列出了你可能用到的每一个正则语法元素,从 \d 和 \b 到后行断言、占有量词和 \p{Script=Greek},每个都有简短的说明和一个准确展示其匹配内容的示例。每个示例都有“在正则表达式测试工具中试用”链接,会打开我们的正则表达式测试工具,并预先填好模式、标志和示例文本,你可以修改它并观察匹配结果的变化。

正则表达式看起来到处都一样,其实并不一样。后行断言在 JavaScript 和 .NET 中不限长度,在 Python 中必须定宽,在 Java 和 PCRE 中有长度上限,在 Go 中则根本没有。Python 的命名分组写作 (?P<name>…),PHP 不能在替换中使用名称,而且只有部分引擎认识 \A、\K 或 (?R)。方言选择器会显示每个语法元素在 JavaScript、PCRE/PHP、Python、Go、Java 和 .NET 中的支持情况,并在有替代语法时一并给出。示例本身在 JavaScript 中运行;对于其他语言,请阅读说明,并在上线前用该语言测试。

使用方法

  1. 搜索某个语法元素(\b、lookahead)或某项任务(email、trim、duplicate words),或通过顶部的标签跳转到相应章节。
  2. 在方言栏中选择你的语言。它不支持的语法元素会被淡化显示,每个条目下的说明会给出你的语言所用的替代语法。
  3. 点击“在正则表达式测试工具中试用”实时运行示例,然后在那里编辑模式或文本。
  4. 使用条目旁边的 # 直接链接到该条目,或使用“打印 / 保存为 PDF”获取紧凑的双栏版本。

常见问题

贪婪量词和懒惰量词有什么区别?

贪婪量词(*、+、{n,m})会尽可能多地匹配字符,如果模式的其余部分匹配失败,再退还一些;懒惰量词(*?、+?、{n,m}?)则尽可能少地匹配。对于 <b>bold</b>,<.+> 会匹配整个字符串,而 <.+?> 会分别匹配 <b> 和 </b>。占有量词(*+、++)是贪婪的,且从不退还字符;JavaScript、Go 和 .NET 没有占有量词。

哪些语言支持后行断言?

JavaScript(自 ES2018 起)和 .NET 允许任意长度的后行断言。Java 要求有长度上限,因此其中不能用 * 或 +。Python 的 re 模块只接受定宽的后行断言。PCRE2 在 10.43 之前要求每个分支长度固定,10.43 加入了有上限(默认 255 个字符)的变长后行断言。Go 的 RE2 引擎完全不支持先行和后行断言。

如何匹配任意字母,包括带重音的字母和非拉丁字母?

使用 Unicode 属性 \p{L}。在 JavaScript 中需要 u 或 v 标志(/\p{L}+/u);PCRE、Go、Java 和 .NET 直接支持。[a-zA-Z] 会漏掉 é、ß 以及所有非拉丁文字,而 \w 在 JavaScript 和 Go 中只匹配 ASCII。Python 内置的 re 没有 \p{…};请使用第三方 regex 模块,或使用 [^\W\d_],它在 Python 3 中匹配 Unicode 字母。

如何在替换中使用捕获分组?

这取决于语言:JavaScript、Java、.NET、Go 和 PHP 用 $1;Python 用 \1 或 \g<1>。命名分组在 JavaScript 中为 $<name>,在 Java、.NET 和 Go 中为 ${name},在 Python 中为 \g<name>;PHP 的 preg_replace 没有命名形式,只能用编号。整个匹配在 JavaScript 和 .NET 中为 $&,在 Java 和 PHP 中为 $0,在 Python 中为 \g<0>。

为什么我的正则在 JavaScript 中能用,在 Python 中却不行(或者反过来)?

常见原因有:命名分组(JavaScript 中为 (?<name>),Python 中为 (?P<name>));\p{…} 属性(JavaScript 支持,Python re 不支持);后行断言长度(JavaScript 任意,Python 固定);内联标志(开头的 (?i) 在 Python 中可用,在 JavaScript 中却是错误,JavaScript 只有限定作用范围的 (?i:…));以及 \d 或 \w 在 Python 中匹配 Unicode 数字和字母,在 JavaScript 中只匹配 ASCII。还要注意 Python 字符串转义:模式要写成原始字符串,r"\d+"。

用正则表达式验证邮箱地址安全吗?

只适合做格式检查。像 [\w.+-]+@[\w-]+(?:\.[\w-]+)+ 这样实用的模式能发现拼写错误,但会拒绝一些合法地址(带引号的本地部分、国际化域名),也会接受一些不合法的地址。没有任何模式能告诉你邮箱是否真实存在,所以宽松地检查格式,然后发送一封确认邮件。

编写可在多种语言中使用的模式

如果一个模式必须在多个引擎中运行(共享的验证规则、由不同语言的服务读取的配置文件),就只使用公共子集。以下内容在本页的全部六种引擎中行为一致:

• 字面字符、\. 和 \$ 之类的转义,以及字符类 [abc]、[^abc] 和 [a-z]。

• \d、\s 和 \w,前提是输入为 ASCII(Python 和 .NET 也会匹配 Unicode 数字和字母)。

• ^ 和 $、\b、选择分支、捕获分组和非捕获分组。

• 贪婪和懒惰量词:*、+、?、{n}、{n,m} 及其带 ? 的形式。

避免使用环视(Go 不支持)、反向引用(Go 不支持)、占有量词和原子分组(JavaScript、Go 和 .NET 缺少其中之一或两者)、命名分组(Python 语法不同)以及 \p{…}(Python 的 re 不支持)。如果需要用到其中某项,就为每种语言各保留一份模式,并分别测试。

避免灾难性回溯

回溯型引擎(JavaScript、PCRE、Python、Java、.NET)在某些模式上可能耗费指数级的时间——当一个带量词的分组能以多种方式匹配同一段文本时,例如 (a+)+$ 或 (\w|\d)*x。面对一个几乎能匹配的长输入,引擎会在失败前尝试每一种拆分方式,Web 服务器可能因此卡死在一个请求上。这就是正则表达式拒绝服务(ReDoS)问题。

修复方法很机械:避免对相同字符嵌套量词;让各选择分支互斥;在知道分隔符时,用 [^"]* 这样的否定字符类代替 .*?;在引擎支持时使用占有量词或原子分组;匹配前限制输入长度。.NET 还提供 RegexOptions.NonBacktracking 和匹配超时,PCRE 可以设置匹配上限,而 Go 的 RE2 引擎通过不支持需要回溯的功能来保证线性时间。

在字符串中转义正则表达式

实际代码中的大多数正则 bug 其实是字符串转义 bug,而不是正则本身的 bug。反斜杠对语言的字符串字面量和正则引擎都有特殊含义,所以写成普通字符串的模式需要双反斜杠。

• JavaScript:字面量 /\d+/ 需要一个反斜杠;new RegExp("\\d+") 需要两个。String.raw`\d+` 可以避免加倍。

• Python:始终使用原始字符串 r"\d+";否则 "\b" 是退格字符,而不是单词边界。

• Java 和 C#:普通字符串中写作 "\\d+"(Java 文本块同样会处理转义);C# 的逐字字符串 @"\d+" 会原样保留反斜杠。

• Go:配合 regexp.MustCompile 时,惯例是使用反引号原始字符串 `\d+`。

• PHP:模式包含分隔符 '/\d+/',单引号字符串会原样保留大多数反斜杠。

相关免费工具

  • 正则表达式测试 — 用示例文本测试正则表达式,实时高亮匹配结果,显示捕获组并预览替换效果。免费,在浏览器中运行。
  • Git 速查表 — 按你想做的事整理 Git 命令:撤销上一次提交、重命名分支、删除远程分支。优先给出新式 switch/restore 命令并附经典写法,危险操作有醒目标记。
  • Markdown 速查表 — 每个 Markdown 元素都附源码和渲染预览,涵盖扩展语法(表格、任务列表、脚注、数学公式、Mermaid、提示框),另有 9 个平台的兼容性对照表和实时练习区。
  • Cron 表达式生成器 — 用下拉菜单生成 cron 定时计划,或粘贴现有表达式,用通俗语言解读,并查看接下来 10 次运行时间(本地时区和 UTC)。免费,在浏览器中运行。
  • 文本对比(Diff) — 比较文本、代码或 JSON 文件的两个版本,准确看出哪些行、词和字符发生了变化。