正则表达式测试工具
在分隔符 / / 之间输入表达式,匹配会随着输入实时高亮:g i m s u y 用开关切换,每处命中都会列出对应的编号与命名捕获组,替换结果也可直接复制。
替换遵循 JavaScript String.replace 语义:$& 表示整段匹配,$1…$99 是编号捕获组,$<name> 是命名捕获组;像 $$ 这样的特殊序列由引擎解析成一个字面量 $。替换结果始终是纯文本,不会被当作 HTML。
匹配结果
| 序号 | 索引 | 匹配内容 | 捕获组 |
|---|
正则表达式速查表
- . \. .*
- 点号匹配除换行符之外的任意单个字符,加上 s 修饰符后才能跨行。它并不是普通句点,所以 1.49 同样会命中 1x49;要匹配小数点请写成 1\.49。
- \b
- 单词边界是零宽断言:只判断位置、不消耗字符。\bcat\b 能匹配 cat 和 cat.,但不会匹配 category。由于下划线属于单词字符,\bfoo\b 在 my_foo 中并不会命中 —— 这正是边界莫名失效的常见原因。
- \d \w \s
- 这三个简写各自匹配一个字符,分别对应数字、单词字符(字母数字下划线)和空白,大写形式 \D \W \S 是取反。在 JavaScript 里它们都只覆盖 ASCII:\w 不会匹配汉字或带重音的字母,处理中文请加上 u 后改用 \p{L} 或 \p{Script=Han}。
- ^ $
- 锚点。不带 m 时它们只对应整段文本的首尾,因此在别处按行调试好的表达式到这里会看起来不生效。另外 JavaScript 比 Python 更严格一点:$ 只匹配真正的结尾,不会匹配末尾换行符之前的位置 —— 请先去掉尾部换行,或者加上 m。
- 贪婪与懒惰
- 量词默认是贪婪的:.* 会尽量多吃,只要剩下的部分还能匹配,所以 "<.*>" 作用于 a<b>c<d>e 时会把两个标签一起吞掉。后面再加 ? 变为懒惰 —— "<.*?>" 只到第一个 > 就停 —— 但懒惰只代表尽可能少,不等于正确,通常写成排除型字符集合 "<[^>]*>" 更快也更清晰。
- [ ]
- 字符集合只匹配一个字符:[abc]、[a-z]、[^0-9]。方括号内 . | ( ) 都不再有特殊含义,- 用于表示区间(要匹配连字符请把它放在最前或最后),只有 \、]、^、- 需要小心。集合本身仍只是一个字符,要重复请写 [0-9]+。
- ( ) (?<name>) (?:)
- 普通圆括号既分组又捕获,编号按左括号出现的顺序确定,可在替换里用 $1 引用。(?<year>…) 给组起名,让 $<year> 比 $2 更好读;(?:…) 只分组不捕获,当你只是为了包住一个分支结构时就该用它。
- a | b
- 选择运算符的优先级最低,因此 cat|dog food 实际是匹配 cat 或者 dog food,而不是 cat food 与 dog food。请把真正想分组的内容括起来:(?:cat|dog) food。
- (?=) (?!)
- 前瞻只检查后面的内容、不消耗字符,是把多个条件组合起来的常用写法:(?=.*\d)(?=.*[A-Z])\S{8,} 读作至少一个数字、一个大写字母、总长八位以上。主流 JavaScript 引擎也已支持后顾 (?<=…) 与 (?<!…)。
- $& $1 $<name> $$
- 替换串里 $& 是整段匹配,$1…$99 是编号捕获组,$<name> 是命名捕获组,$$ 会被折叠成一个字面量 $。如果引用的组在表达式里并不存在,这段记号会原样保留;替换结果始终是纯文本,不会被解析成 HTML。
使用方法
- 在「正则表达式」框中输入表达式本体——两侧的斜杠只是为了看得清楚而显示,请不要输入斜杠;也可以直接点击「载入示例」,用一组真实日志和已经能命中它的表达式开始。
- 切换 g、i、m、s、u、y 开关。每个开关都会显示自己的字母,下方提示行会说明当前生效的修饰符各自改变了什么,你的选择下次打开时仍然保留。
- 查看测试文本下方的「高亮预览」和位置标尺(^ 行:列),再对照「匹配结果」表格:每处匹配一行,包含索引、匹配内容与捕获组,未参与的组会明确显示为 (未匹配)。
- 填写「替换内容」即可看到替换结果;选中表达式片段后点击「转义特殊字符」可自动转义元字符,最后用「复制」取出结果,或点击「清空」重新开始。
常见问题
为什么正则在这里能匹配,在我代码里却不行?
这里运行的是浏览器内置的 ECMAScript 正则引擎,并不是 PCRE 或 Python。具体差别有:\d、\w、\s 只覆盖 ASCII,匹配中文或带重音的字母需要加上 u 并改用 \p{L};$ 只匹配整段文本的真正结尾,不像 Python 那样还能匹配末尾换行符之前;命名组写法是 (?<name>…) 和 \k<name>,Python 的 (?P<name>) 会直接报错;把带 // 分隔符的整串复制过来也会匹配不到。另外在 Python 源码里字符串本身会吃掉反斜杠,请写成 r"\d+"。
为什么一处都匹配不到?
常见原因有三类。其一是修饰符:不加 m 时 ^ 和 $ 只对应整段文本的首尾,按行调试好的表达式遇到多行文本就会失效,不加 g 则只看第一处。其二是贪婪:.* 会尽量多吃,"<.*>" 作用于两个标签时会把中间全部内容吞掉,应改用 "<.*?>",更好的写法是 "[^>]*"。其三是优先级:选择运算符最低,cat|dog food 其实只匹配 cat 或 dog food。若表达式本身语法有误,状态行会给出引擎原始报错并附排查提示;而匹配过宽的表达式会被限制渲染数量,不会让页面卡死。
我的表达式和文本会被传走吗?
不会。匹配、高亮和替换全部在当前页面内由浏览器自身的正则引擎完成,组件没有任何运行时依赖,也不会发起网络请求,页面加载后断网依然可用。因此用它测试包含真实邮箱、IP 或令牌的日志与接口数据同样是安全的。