正则逻辑

正则引擎是如何思考的

匹配过程:正则匹配的过程就像是一辆只能前进和后退(回溯)的汽车,在字符串这条路上行驶,根据规则(正则)进行匹配。

理解引擎如何工作,是写出高效正则的关键。其核心是​​回溯机制​​。

  1. ​贪婪模式(Greedy) - 默认行为​

    • ∙​​原则​​:量词(*, +, ?, {m,n})会​​匹配尽可能多的字符​​。

    • ∙​​过程​​:先“吃掉”所有能匹配的字符,然后为了满足后续的模式,再​​一点点“吐出来”(回溯)​​,直到后续模式也能匹配成功。

    • ∙​​示例​​:正则 a.*b 匹配字符串 "axxyb"

      • a 匹配第一个 a

      • .*​贪婪地匹配所有字符​​:a -> ax -> axx -> axxy -> axxyb ✅(但此时 .* 也“吃掉”了 b

      • ∙引擎发现模式后面还有个 b,但字符串末尾已无字符。于是开始​​回溯​​。

      • .* 吐出最后一个字符 b,尝试用模式中的 b 去匹配它,成功! ✅

      • ∙​​最终匹配​​:axxyb

  2. ​懒惰模式(Lazy/Reluctant) - 量词后加 ?

    • ∙​​原则​​:量词会​​匹配尽可能少的字符​​。

    • ∙​​过程​​:先匹配最少必需的字符,如果后续模式失败,再​​多“吃”一个字符​​,直到整体匹配成功。

    • ∙​​示例​​:正则 a.*?b 匹配字符串 "axxyb"

      • a 匹配第一个 a

      • .*?​懒惰地匹配最少的字符(0个)​​,剩下 "xxyb"

      • ∙尝试用 b 匹配剩下的第一个字符 x,失败 ❌。

      • .*? 被迫多匹配一个字符 x,剩下 "xyb"

      • ∙尝试用 b 匹配 x,失败 ❌。

      • .*? 再匹配一个 x,剩下 "yb"

      • ∙尝试用 b 匹配 y,失败 ❌。

      • .*? 再匹配一个 y,剩下 "b"

      • ∙尝试用 b 匹配 b,成功! ✅

      • ∙​​最终匹配​​:axxyb (结果和贪婪模式一样,但过程更耗时)

  3. ​独占模式(Possessive) - 量词后加 +(部分引擎支持,如Java)​

    • ∙​​原则​​:类似贪婪模式,但​​一旦匹配就绝不回溯​​。

    • ∙​​过程​​:匹配尽可能多的字符,然后​​锁死​​,不允许回溯。如果后续模式不匹配,则整体直接失败。

    • ∙​​示例​​:正则 a.*+b 匹配字符串 "axxyb"

      • a 匹配第一个 a

      • .*+​贪婪且独占地匹配所有字符​​:a -> ax -> ... -> axxyb

      • ∙引擎发现模式后面还有个 b,但字符串已无剩余字符。

      • ∙因为 .*+ 是独占的,拒绝回溯。

      • ∙​​整体匹配失败​​ ❌

注意:正则中有部分元素是不消耗字符的。注意使用下列元素时锚点的使用

类型
语法
名称
作用
示例

​锚点​

^

起始锚点

匹配字符串的​​开始位置​

^abc 匹配以 "abc" 开头的字符串

$

结束锚点

匹配字符串的​​结束位置​

xyz$ 匹配以 "xyz" 结尾的字符串

\b

单词边界

匹配单词的​​开始或结束位置​​(\w和\W之间)

\bword\b 匹配独立的单词 "word"

\B

非单词边界

匹配​​不是​​单词边界的位置

\Bword\B 匹配 "swordfish" 中的 "word"

​前瞻断言​

(?=...)

正向先行断言

匹配​​后面​​是...的位置

X(?=YZ) 匹配后面是 "YZ" 的 "X"

(?!...)

负向先行断言

匹配​​后面不是​​...的位置

X(?!YZ) 匹配后面不是 "YZ" 的 "X"

​后顾断言​

(?<=...)

正向后行断言

匹配​​前面​​是...的位置

(?<=AB)X 匹配前面是 "AB" 的 "X"

(?<!...)

负向后行断言

匹配​​前面不是​​...的位置

(?<!AB)X 匹配前面不是 "AB" 的 "X"

正则表达式
匹配结果
说明

A.*3

"ABC123"

.*​消耗字符​​,匹配了中间的所有内容

A(?=B).*3

"ABC123"

(?=B)​不消耗字符​​,只检查A后面是B,然后从A开始继续匹配

(?<=A).*3

"BC123"

(?<=A)​不消耗字符​​,只定位在A后面,然后从B开始匹配

正则模式说明

模式符号

名称

核心作用

匹配示例

i

忽略大小写 (Ignore Case)

匹配时不区分英文字母的大小写。

/apple/i 可匹配 Apple, APPLE, aPpLe

g

全局匹配 (Global)

找到所有匹配项,而不是在找到第一个后停止。

"aba".match(/a/g) 结果为 ["a", "a"]

m

多行模式 (Multiline)

使 ^$ 匹配每一行的开头和结尾。而不仅仅是整个字符串的开头和结尾。

在多行文本中,/^A/m 可匹配每行行首的 A

s

单行模式 (DotAll)

使点号 . 可以匹配包含换行符在内的所有字符。

"a\nb".match(/a.b/s) 匹配成功

u

Unicode模式

正确处理 4 字节的 UTF-16 字符(如表情符号)。

/\u{61}/u 匹配字母 a,支持复杂字符

y

粘性模式 (Sticky)

从正则表达式的 lastIndex 属性指定的索引开始匹配。

严格从当前位置开始,不向后搜索

最后更新于