关于实现正则表达式引擎背后的实用问题的权威参考是Russ Cox撰写的三篇博客文章系列。如此处所述,由于反向引用使您的语言变得不规则,因此可以使用backtracking来实现它们。
像正则表达式模式匹配引擎的许多功能一样,前瞻性和后顾之忧不太适合确定字符串是否为语言成员的范式。通常使用正则表达式来搜索较大字符串中的子字符串。“匹配”是属于该语言的子字符串,返回值是较大字符串中子字符串的起点和终点。
先行和后退的目的不是引入匹配非常规语言的功能,而是调整引擎报告匹配子字符串的起点和终点的位置。
我依靠http://www.regular-expressions.info/lookaround.html上的描述。支持此功能的正则表达式引擎(Perl,TCL,Python,Ruby等)似乎都是基于回溯的(即,它们支持的语言集比常规语言要大得多)。他们似乎将此功能实现为回溯的相对“简单”扩展,而不是尝试构造真正的有限自动机来执行任务。
积极向前
对于语法正向前查找是(?=
正则表达式)
。因此,例如,q(?=u)
相匹配q
,只有当它后面u
,但不匹配u
。我想他们会通过回溯的方式来实现这一目标。在正向超前前为表达式创建FSM。当匹配时,记住它的结束位置并开始一个新的FSM,该FSM表示正向超前的表达式。如果匹配,则您有一个“匹配”,但匹配在正超前匹配开始的位置之前“结束”。
唯一没有回溯就很难的部分是,您需要记住输入中超前开始的点,并在完成匹配后将输入磁带移回到该位置。
负前瞻
否定超前的语法是(?!
regex)
。因此,例如,仅在不带时q(?!u)
匹配。这可以是后面跟一些其他字符,也可以是字符串的结尾。我想这是通过为先行表达式创建NFA来实现的,然后仅在NFA无法匹配后续字符串时才成功。q
u
q
q
如果要在不依赖回溯的情况下执行此操作,则可以否定超前表达的NFA,然后以与对待正向超前相同的方式对其进行处理。
正向后看
(?<=
)
(?=q)u
u
q
q
ñnn
通过将“以regex结尾的字符串”与lookexhind运算符之前的regex的任何部分相交,您也许可以实现此功能而无需回溯。但是,这将很棘手,因为向后的正则表达式可能需要向后看,而不是当前输入的开始。
负向后看
对于语法负回顾后是(?<!
正则表达式)
。因此,例如,(?<!q)u
匹配u
,但前提是它前面没有q
。因此它将与u
in umbrella
和u
in相匹配doubt
,但与u
in 不匹配quick
。再次,这似乎是通过计算regex的长度,备份那么多字符,使用regex测试匹配来完成的,但是如果lookbehind匹配,则整个匹配失败。
通过排除正则表达式,然后执行与进行正向后看相同的操作,您可以实现此功能而无需回溯。