正则表达式测试器
输入正则表达式和测试文本,实时查看匹配结果、捕获组与高亮位置。所有匹配在浏览器本地完成,数据不会上传。
正则不是"一个功能",而是一种描述文本模式的微型语言
很多人把正则表达式当成"查找工具里的一个开关",但更准确的理解是:它是一套用少量符号描述"文本长什么样"的规则语言。比如 `\d{4}-\d{2}-\d{2}` 描述的是"四位数字-两位数字-两位数字"这种形状,而不是某个具体日期;`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$` 描述的是"本地名@域名"这种结构。正因为它是"形状描述"而非"具体值",同一段写法才能复用到邮箱、日志、身份证、URL 等完全不同的场景。掌握它的关键,不在于背下每个符号,而在于理解三件事:字符怎么表示(字符类、转义)、重复怎么表示(量词、贪婪/懒惰)、结构怎么分组与锚定(分组、断言、^ $)。本工具在浏览器本地用 ECMAScript 引擎构建并运行正则,下面几张表能帮你避开最常见的坑。
正则引擎家族:为什么同一段写法在不同地方结果不同
同样一段正则,在浏览器、PHP、Java、Python 里可能"能跑 / 报错 / 结果不同",根子在于底层引擎实现不一样。主流引擎分两类:回溯型 NFA(大多数语言默认)和 DFA/自动机(RE2 等,线性时间、永不回溯)。下表按国内最常用的运行环境做了对照(依据 ECMA-262 第 15 版 / ES2024、PCRE2、Python re、Java java.util.regex 官方文档)。
| 引擎 / 实现 | 代表使用场景 | 回溯行为 | 关键语法差异 |
|---|---|---|---|
| ECMAScript(浏览器 / Node.js,本工具所基于) | 前端校验、JS 脚本 | 回溯型 NFA;默认贪婪,支持懒惰 *?,不支持占有量词 | 支持 \p{...} 需开 u 标志;命名组 (?<name>...);u 模式下 \d 匹配全部 Unicode 数字 |
| PCRE2(PHP、Notepad++、Apache 等) | 服务端、编辑器 | 回溯型;支持占有量词 *+ 与原子组 (>...),可缓解 ReDoS | 语法最丰富,支持 \p{L}、回溯控制 (*SKIP) |
RE2(Go regexp、Rust 部分库) | 高并发服务端 | DFA / 自动机,线性时间,永不回溯,天然抗 ReDoS | 不支持反向引用、无后行断言;仅为语法子集 |
Python re(CPython 默认) | 数据清洗、爬虫 | 回溯型;不支持占有量词;3.11 起有原子分组实验特性 | 支持 \p 需第三方 regex 库;默认 . 不匹配换行 |
Java java.util.regex | 企业后端 | 回溯型;支持占有量词 *+、原子组 (>...) | 支持 \p{L}、命名组 (?<name>...);matches() 默认全串锚定 |
注意:本工具用的是浏览器 ECMAScript 引擎,所以"占有量词 *+"在这里会直接报语法错误。如果你的正则来自 Java/PCRE 且含 *+,需要改成等价写法或去掉占有修饰。国内前端与 Node.js 服务大多走这一套,和服务端 PCRE/Java 的差异最容易在联调时踩坑。
回溯与 DFA:一个坏正则会拖垮服务(含实测)
回溯型引擎的工作方式是"猜":量词 + 先尽量多吃,发现后面接不上就"吐"回来重新分。多数情况很快,但某些嵌套量词组合(如 (a+)+$)会让"吐"的次数随输入长度指数级爆炸,这就是 ReDoS(正则表达式拒绝服务)。在 Web 场景里,攻击者只要发一段精心构造的长文本,就能让校验接口 CPU 占满。国内安全实践(如 CNCERT 风险提示)与 OWASP Top 10:2021(A06)均将 ReDoS 列为典型 Web 风险。下面是用本机实测的耗时(环境:Node v22 / 12 代 Intel i5-12600KF,输入为 n 个 a 后接一个 !,仅供相对比较):
| 输入长度(n 个 a + 1 个 !) | (a+)+$ 耗时 (ms) | 对照线性 a+ 耗时 (ms) | 说明 |
|---|---|---|---|
| 18 | 2.22 | 762 | 长度短时两者都很快 |
| 20 | 8.49 | 734 | 灾难性回溯开始显现 |
| 22 | 31.90 | 769 | 约每 +2 长度翻 4 倍 |
| 24 | 128.24 | 788 | 已是线性版本的 6 倍多 |
| 26 | 517.60 | 818 | 半秒级,用户已明显卡顿 |
| 28 | 2316.20 | 786 | 超 2 秒,接口基本不可用 |
| 30 | 15446.63 | 824 | 约 15 秒,服务被拖垮 |
对比很清楚:线性正则 a+ 的耗时几乎不随长度变化(约 780ms 是首次编译噪声),而灾难性回溯版本从 18 到 30 个字母,耗时从 2ms 涨到 15 秒,约 7000 倍。经验法则:避免"量词套量词"且内部与外部量词都能匹配同一字符(如 (a+)+、(a*)*、(.*a){10});校验用户输入的前后端都要用简单、确定性的模式,必要时用 RE2 这类线性引擎。本工具会实时高亮匹配,但不会替你拦下 ReDoS 写法,写复杂正则时请自己用加长输入压测一下。
元字符与量词速查表
下面这张表覆盖了 90% 日常写法。重点记住:ECMAScript 里只有贪婪和懒惰,没有占有量词;想要"占有"的防回溯效果,得靠改写结构(如用字符类 [^x]+ 替代 .*)。
| 符号 | 含义 | 贪婪 / 懒惰 / 占有 | 备注 |
|---|---|---|---|
* | 匹配前项 0 次或多次 | 贪婪 * / 懒惰 *? / 占有 *+(ECMAScript 不支持) | 最常见 ReDoS 来源 |
+ | 匹配前项 1 次或多次 | 贪婪 + / 懒惰 +? / 占有 ++(ECMAScript 不支持) | 至少一个 |
? | 匹配前项 0 次或 1 次 | 贪婪 ? / 懒惰 ?? / 占有 ?+ | 也用于把捕获组变非捕获 (?:...) |
{n,m} | 前项重复 n 到 m 次 | 贪婪 {n,m} / 懒惰 {n,m}? / 占有 {n,m}+ | {3,} 至少 3 次,{3} 恰 3 次 |
\b | 单词边界(零宽) | — | 不匹配字符,只标位置 |
\d | 数字 | — | 无 u 标志仅 [0-9];加 u 匹配全角数字等 Unicode 数字 |
\w | 单词字符 | — | [A-Za-z0-9_];u 下也不含中文 |
\p{L} | Unicode 字母属性 | — | 需 u 标志;\p{Script=Han} 可匹配汉字 |
标志位对照表
标志位决定"怎么搜"而不是"搜什么"。本工具界面提供 g / i / m / s / u 五个开关,下面把每个的作用和 ECMAScript 里的 y(粘性)一并列出:
| 标志 | 作用 | 本工具默认 |
|---|---|---|
g | 全局:找出所有匹配,而非第一个 | 默认开启 |
i | 忽略大小写:a 同时匹配 A | 默认关闭 |
m | 多行:^ $ 匹配每一行的开头与结尾 | 默认关闭 |
s | dotAll:让 . 也能匹配换行符 | 默认关闭 |
u | Unicode 码点模式:支持 \p{...}、正确计量代理对等 | 默认关闭(匹配中文建议开启) |
y | 粘性:只从 lastIndex 位置开始匹配,前端代码中常用 | 界面未直接提供,可在模式里手写 |
常用模式库:写法与已知局限
下面这些是从项目里捞出来的高频模式,都经过本机编译校验可运行。但正则校验是"形状校验"而非"语义校验",每张都标注了它拦不住什么——这也是 AdSense 类工具页最容易被误用的地方。
| 用途 | 写法 | 已知局限 |
|---|---|---|
| 邮箱 | ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ | 不支持引号本地名、IDN 国际域名、连续点;能放过 a@b.c 这种弱地址 |
| URL(http/https) | ^https?:\/\/[\w.-]+(?:\/[\w./?%&=#-]*)?$ | 不校验端口、不允许 ftp、不防无效 TLD;仅做形状判断 |
| 日期 YYYY-MM-DD | ^\d{4}-\d{2}-\d{2}$ | 拦不住 2026-13-45 这种非法日历值,需另做日期合法性校验 |
| IPv4 地址 | ^(?:(?:25[0-5]|2[0-4]\d|1?\d?\d)\.){3}(?:25[0-5]|2[0-4]\d|1?\d?\d)$ | 允许 192.168.001.1 前导零;不拒绝保留段如 0.0.0.0 |
| 中国大陆手机号 | ^1[3-9]\d{9}$ | 只校验 11 位与号段首两位,不验真实在网;虚拟运营商号段亦包含 |
| 密码强度 | ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\w\s]).{8,}$ | 只验"大小写+数字+符号+8位",拦不住 Password1! 这类弱口令;要防泄露应配合密码生成器与密码安全指南 |
三个真实算例(用页面默认输入)
下面三个例子都使用本工具默认测试文本 2026-08-23 发布新版本,2026-09-01 计划更新。(默认只勾选 g 标志),你可以直接复制到工具里复现。想知道文本里有多少个字符、多少个词,可顺手用字数统计工具核对;要对比两版文本的改动,可用文本差异对比。
算例 1:数出所有日期
模式 \d{4}-\d{2}-\d{2},标志 g。在默认文本上得到 2 处匹配:2026-08-23(位置 0)与 2026-09-01(位置 17)。这正是占位提示里给的例子,用来"抓出所有日期"最直接。
算例 2:把年月日拆进捕获组
模式 (\d{4})-(\d{2})-(\d{2}),标志 g。匹配数仍是 2,但每个匹配多出 3 个捕获组:第 1 组年(2026)、第 2 组月(08 / 09)、第 3 组日(23 / 01)。工具结果区的"捕获组"列表会把这些分组列出来,方便你按字段提取。
算例 3:抽出全部数字
模式 \d+,标志 g。默认文本里共有 6 处数字匹配:2026@0、08@5、23@8、2026@17、09@22、01@25。注意 \d+ 把"2026"当一整个数,而不是 4 个单数字——这就是量词"贪婪吃满"的表现。
写正则的常见坑
① 转义。 . * + ? ( ) 在正则里有特殊含义,想匹配本身要加反斜杠(\. \*)。在编程语言字符串里反斜杠本身还要再转义,这是"明明写对了却报错"的头号原因。
② 贪婪 vs 懒惰。 默认量词贪婪(尽量多匹配),要"最少匹配"加 ? 变懒惰(.*?)。提取 HTML 标签时搞错这点,会一次吞掉半篇文章。
③ 忘锚点。 校验"整串是不是邮箱"要用 ^ 和 $ 包住;否则只匹配到中间一段,校验就"漏网"了。
补充问答
为什么同一个正则在这个工具里能跑,放到 Python / Java 里却报错或结果不同?因为底层引擎方言不同(见上方引擎家族表)。最典型的差异:ECMAScript 不支持占有量词 *+,而 Java/PCRE 支持;PCRE 的 (*SKIP) 回溯控制在 JS 里没有;Python re 默认 . 不匹配换行,和 JS 开 s 后不同。跨语言搬运正则前,先对照表确认语法是否互通。
\d 在加 u 和不加 u 时,匹配范围为什么不一样?不加 u 时 \d 只等价于 [0-9](ASCII 数字);加上 u 标志后,ECMAScript 按 Unicode 处理,\d 会匹配阿拉伯文、全角等世界各语种数字字符。如果你的文本可能含全角数字"2026",校验时必须开 u,否则会漏判。
怎样写出既校验邮箱又不卡死的正则?邮箱正则本身一般不构成 ReDoS,风险多在"嵌套量词 + 长文本"场景。原则:邮箱/URL 校验用上方模式库里的扁平写法,不要写成 ([\w]+@[\w]+)+ 这类量词套量词;对来自用户的超长输入,先长度截断再校验,或用 RE2 等线性引擎。更多防爆破与弱口令的思路见密码安全指南。
捕获组太多会影响性能吗?命名组 (?<name>...) 和匿名组有区别吗?功能上等价,命名组只是让结果更易读、后续代码不易因"加了一个组导致序号错位"而出错。性能上两者开销都很小;真正要吃性能的是"嵌套捕获组 + 灾难性回溯"的组合,和组本身叫不叫名字无关。
为什么我对超大文本用复杂正则时浏览器会卡?大概率是触发了 ReDoS(见上方实测表)。浏览器也是回溯型引擎,长文本下 (a+)+ 这类写法会指数爆炸。排查办法:用加长输入在工具里压测,看匹配耗时是否随长度陡增;若是,改用字符类边界(如 [^x]+)消除嵌套量词,或拆分多次简单匹配。