正则逻辑
正则引擎是如何思考的
匹配过程:正则匹配的过程就像是一辆只能前进和后退(回溯)的汽车,在字符串这条路上行驶,根据规则(正则)进行匹配。
理解引擎如何工作,是写出高效正则的关键。其核心是回溯机制。
贪婪模式(Greedy) - 默认行为
∙原则:量词(
*,+,?,{m,n})会匹配尽可能多的字符。∙过程:先“吃掉”所有能匹配的字符,然后为了满足后续的模式,再一点点“吐出来”(回溯),直到后续模式也能匹配成功。
∙示例:正则
a.*b匹配字符串"axxyb"∙
a匹配第一个a✅∙
.*贪婪地匹配所有字符:a->ax->axx->axxy->axxyb✅(但此时.*也“吃掉”了b)∙引擎发现模式后面还有个
b,但字符串末尾已无字符。于是开始回溯。∙
.*吐出最后一个字符b,尝试用模式中的b去匹配它,成功! ✅∙最终匹配:
axxyb
懒惰模式(Lazy/Reluctant) - 量词后加
?∙原则:量词会匹配尽可能少的字符。
∙过程:先匹配最少必需的字符,如果后续模式失败,再多“吃”一个字符,直到整体匹配成功。
∙示例:正则
a.*?b匹配字符串"axxyb"∙
a匹配第一个a✅∙
.*?懒惰地匹配最少的字符(0个),剩下"xxyb"。∙尝试用
b匹配剩下的第一个字符x,失败 ❌。∙
.*?被迫多匹配一个字符x,剩下"xyb"。∙尝试用
b匹配x,失败 ❌。∙
.*?再匹配一个x,剩下"yb"。∙尝试用
b匹配y,失败 ❌。∙
.*?再匹配一个y,剩下"b"。∙尝试用
b匹配b,成功! ✅∙最终匹配:
axxyb(结果和贪婪模式一样,但过程更耗时)
独占模式(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 属性指定的索引开始匹配。
严格从当前位置开始,不向后搜索
最后更新于