零宽度断言的关键知识点

来源:互联网 发布:java生成随机整数 编辑:程序博客网 时间:2024/06/13 09:57

正则表达式的匹配是从字符串的开头到字符串的结尾,在引擎看来,字符串 “str” 是这个样子的形式:^s@t@r$ , ^ 表示字符串开头的位置,即第一个字符之前的位置,@ 表示字符之间的位置,$ 表示字符串末尾的位置,即最后一个字符之后的位置。匹配是从一个位置移动到下一个位置,假设正则表达式为 tr,我们在字符串 “str” 中寻找其匹配,首先,引擎会指向 ^ 位置,将 t 与当前字符 s 做对比(”当前字符”是指当前位置之后的第一个字符),发现不符,引擎便指向 下一个位置,即 @ 位置,即字符 s 之后的位置,然后继续用 t 与当前字符 t 做比较,发现相同,引擎继续移向下一个位置,即第二个 @ 位置,并用 r 与当前字符 r 做比较,发现相同,至此,正则匹配结束。

位置的概念是很重要的,尤其在理解零宽度断言的时候,因为零宽度断言就是判断某个”位置”是否符合条件,举个简单例子,假设正则表达式为 s(?=t),我们依然在字符串 “str” 中寻找其匹配,首先需要注意的是,s(?=t) 只匹配一个字符,因为(?=t)的宽度为”零”。匹配过程是这样的:引擎首先指向 ^ 位置,然后用 s 与当前字符 s 做比较,发现相同,然后引擎指向第一个 @ 位置,在该位置上应用零宽度断言 (?=t) 判断当前字符 t 是否等于 t,发现等于,则匹配成功,最后的匹配结果是 s 。下面对正则表达式稍做些变形,观察匹配结果是什么:

变形1:正则表达式为 s(?!t),引擎的匹配过程如下:
引擎首先指向 ^ 位置,然后用 s 与当前字符 s 做比较,发现相同,然后引擎指向第一个 @ 位置,在该位置上应用零宽度断言 (?!t) 判断当前字符 t 是否不等于 t,发现等于,说明匹配失败,最终结果是没有找到任何匹配。

变形2:正则表达式为 s(?=t)r,引擎的匹配过程如下:
引擎首先指向 ^ 位置,然后用 s 与当前字符 s 做比较,发现相同,然后引擎指向第一个 @ 位置,在该位置上应用零宽度断言 (?=t) 判断当前字符 t 是否等于 t,发现等于,说明匹配成功,接着引擎在当前位置匹配 r (注意,这里的当前位置仍然是第一个 @ 位置,因为 (?=t) 的宽度为0,所以引擎在匹配完 (?=t) 后没有移动引擎指针),所以接着引擎会用 r 与当前字符 t 做比较,发现匹配失败,最终匹配结果也是没找到任何匹配。

变形3:正则表达式为 s(?=t)t,引擎的匹配过程如下:
引擎首先指向 ^ 位置,然后用 s 与当前字符 s 做比较,发现相同,然后引擎指向第一个 @ 位置,在该位置上应用零宽度断言 (?=t) 判断当前字符 t 是否等于 t,发现等于,说明匹配成功,接着引擎在当前位置匹配 t (注意,这里的当前位置仍然是第一个 @ 位置,因为 (?=t) 的宽度为0,所以引擎在匹配完 (?=t) 后没有移动引擎指针),所以接着引擎会用 t 与当前字符 t 做比较,发现匹配成功,最终匹配结果是 st 。

变形4:正则表达式为 (?=s)t,引擎的匹配过程如下:
引擎首先指向 ^ 位置,然后应用零宽度断言 (?=s) 用 s 与当前字符 s 做比较,发现相同,然后引擎停留在当前位置,并 判断当前字符 s 是否等于 t,发现不等于,说明匹配失败,最终匹配结果是没有找到任何匹配 ,其实上述正则表达式永远都无法匹配成功。

变形5:正则表达式为 (?=s)s,引擎的匹配过程如下:
引擎首先指向 ^ 位置,然后应用零宽度断言 (?=s) 用 s 与当前字符 s 做比较,发现相同,然后引擎停留在当前位置,并 判断当前字符 s 是否等于 s,发现不等于,说明匹配成功,最终匹配结果是:s

最后举一个稍微复杂点的例子:字符串为 “a stop b”
正则表达式1:.*(?=\bstop\b),匹配结果:”a ” (注意,a 的后面还有个空格)
正则表达式2:(?=\bstop\b).*,匹配结果:”stop b”

特别需要理解的其实就是一点:零宽度断言是判断”位置”是否满足条件,当零宽度断言完成匹配后,引擎会停留在原来的位置,接着进行下一步的匹配。

0 0
原创粉丝点击