环视

只看不吃:先行断言(lookahead)和后行断言(lookbehind)是零宽断言,检查某个位置前后的内容,然后退回原位,让真正的匹配继续。

阅读规则:指南中的“先行断言与后行断言” →反复操练:正则魔法 →

本课程建立在分组与反向引用之上

你将学到

先行断言 负向先行断言 后行断言 负向后行断言 密码规则

步骤 · 12

  1. 01只看不吃讲解
  2. 02正向先行断言狩猎
  3. 03用先行断言找一个字符狩猎
  4. 04负向先行断言狩猎
  5. 05“后面不是”狩猎
  6. 06正向后行断言狩猎
  7. 07负向后行断言狩猎
  8. 08组合断言狩猎
  9. 09更严格的密码狩猎
  10. 10不以 s 结尾的单词狩猎
  11. 11高尔夫:q 后面不是 u狩猎
  12. 12断言已掌握讲解

正则中的先行断言与后行断言

环视让正则表达式检查某个位置旁边的文本,却不把它算进匹配结果。它们和锚点一样是零宽的:检查要么通过、要么失败,光标都留在原地。正则的其余部分接着从同一个位置继续,就像刚才那一眼从没看过一样。

先行断言向右看。(?=...) 要求后面的文本匹配,(?!...) 要求它不匹配。后行断言向左看:(?<=...) 要求前面的文本匹配,(?<!...) 要求它不匹配。JavaScript 四种都支持,而且它的后行断言可以是任意长度。

当上下文决定是否匹配、却不该出现在匹配结果里时,就用环视:只在后面跟着单位时才匹配数字,只在缺少某个前缀时才匹配单词,或者对同一个输入施加多条规则,比如密码必须含有一个数字和一个大写字母,顺序不限。在狩猎中,环视常常能放过那些和目标字母完全相同的无辜词。

示例

  1. /\d+(?=px)/

    抓住

    • 12px
    • 300px
    • w: 8px

    放过

    • 12em
    • px12
    • 12 px

    先行断言要求数字后面紧跟 px,但匹配结果本身只有数字。

  2. /(?<=#)\w+/

    抓住

    • #tag
    • go #team
    • #2026

    放过

    • tag
    • # team
    • a#

    后行断言检查左边是否有 #,并把它排除在外,所以匹配到的只是标签本身。

  3. /^(?!.*\d)\w+$/

    抓住

    • hello
    • snake_case

    放过

    • r2d2
    • top10

    负向先行断言先用 .* 扫描整个单词,所以只要其中任何位置有一个数字,就足以拒绝它。

  4. /(?<!re)play/

    抓住

    • play
    • display
    • player

    放过

    • replay
    • replays

    只有当 re 紧挨在前面时,负向后行断言才放过 play。

常见错误

  • 在开头的先行断言里忘了 `. *。^(?=\d) 只检查第一个字符;要表示“任意位置有一个数字”,请写 ^(?=.*\d)`。
  • 以为看过的文本会出现在结果里。 环视从不往匹配里添加字符,所以对 \d+(?=px) 做替换时,换掉的是数字,px 会保留。
  • 把 JavaScript 的后行断言照搬到其他正则引擎。 Python 的 re 模块要求 (?<=...) 里的内容长度固定,许多其他引擎也有类似限制,所以 (?<=\$\d*) 在 JavaScript 中可用,在那里就会出错。

阅读规则:指南中的“先行断言与后行断言” →反复操练:正则魔法 →

延伸阅读:正则表达式的先行断言与后行断言:用可交互棋盘讲清楚 →

延伸阅读:用正则先行断言校验密码规则(以及何时不该这么做) →