04-正则引擎内部初探

理解正则引擎的内部原理将帮助你写出更高效的表达式,并且帮助你快速调试正则表达式中的异常

在接下去的章节中每当我们介绍一个新的正则token,我们都会解释正则引擎是如何处理这个token的。虽然理解引擎的原理有些难度,但是它可以帮助我们避免一些常见的错误。

4.1 引擎的分类

虽然正则引擎有很多种不同的实现,但是大体可以分为两类:文本驱动的引擎(text-directed)和正则驱动的引擎(regex-directed)。几乎所有的现代正则引擎都采用正则驱动引擎,这是因为一些非常有用的特性只能在这种引擎上实现,例如 lazy quantifiersbackreferences

4.1.1 正则驱动的引擎(regex-directed engine)

一个正则表达式引擎通过遍历正则表达式完成匹配,它尝试将表达式中的下一个token和字符串中的下一个字符进行匹配。如果当前token可以匹配到,那么引擎将移动至下一个token,并且把这个token和字符串中的下一个字符进行匹配。如果匹配没有成功,那么正则引擎会在正则和字符串中进行回溯,并且重新进行路径搜索。关于正则的回溯之后的章节会详细展开。现在正则表达式引擎使用atomic groupin possessive quantifiers等特性,是的我们可以控制正则的回溯过程。

4.1.2 文本驱动的引擎(text-directed engine)

一个文本驱动的引擎通过遍历文本完成匹配。在匹配下一个字符之前,他会尝试表达式中的所有排列。一个文本驱动的引擎没有回溯过程,所以他的匹配过程相对简单。在大多数情况下两种引擎的匹配结果是相同的。

本教程主要讨论正则驱动的引擎,所以默认情况下我们提到的引擎都是正则驱动引擎,除非两种引擎的匹配结果不一致。只有当我们使用alternative,并且两个alternatives匹配到同一个位置时才会发生这种情况。

4.2 正则表达式总是匹配最左端的匹配结果

正则表达式总是匹配最左端的匹配结果,无论后面是否有更好的匹配结果,这是一个非常重要的观点。当正则匹配一个字符串的时候,它将从字符串的最左边开始搜索。它将正则中所有的排列与字符串的第一个字符向匹配。如果有一种排列匹配成功,引擎将继续匹配字符串中的下一个字符。下一步引擎将字符串中的下一个字符与正则中的所有排列进行匹配。最终引擎将返回最靠左的匹配结果。

现在我们来举一个例子。我们使用表达式cat去匹配字符串He captured a catfish for his cat。首先引擎使用c去匹配字符串中第一个字符H,此时匹配不成功而且此时没有其他的排列(因为c是一个字面量字符)。之后引擎包ce匹配,也失败了,和空格匹配也是如此。当引擎尝试匹配第四个字符的时候c匹配c成功了,所以引擎继续把第二个tokena与字符串中第5个字符a匹配,匹配也成功了。但是第三个tokent不能和第六个字符p匹配。此时引擎已经知道表达式无法和字符串中的前四个字符匹配,此时c将和第5个字符p进行匹配,直到第15个字符时c才匹配成功,接下来at也匹配成功。

此时这个正则可以从字符串的第15个字符开始匹配成功,于是引擎非常“急切”的报告匹配成功。引擎不会继续向后搜索,因为它认为这个结果已经足够好了。

在这个例子当中正则驱动的引擎和文本驱动的引擎的搜索结果是相同的。正则的这种搜索模式很大程度上决定了它的所搜结果,在之后例子中有一些匹配结果可能使你感到意外,但是只要你牢记这个搜索规则,你就可以用逻辑推导引擎的匹配结果。

如果文章出现错误,请给我提Issues - -
Github地址

原文

猜你喜欢

转载自blog.csdn.net/billll/article/details/84578618
今日推荐