这两个回溯控制动词仅在 Perl、PCRE 和pypi正则表达式模块 https://pypi.python.org/pypi/regex.
的想法(*SKIP)(*FAIL)
技巧是消耗您想要避免的字符,并且这些字符不能成为匹配结果的一部分。
使用此技巧的经典模式如下所示:
What_I_want_to_avoid(*SKIP)(*FAIL)|What_I_want_to_match
正则表达式引擎处理这样的字符串:
从左到右对每个字符测试模式的第一个标记(大多数时候默认情况下,但是一些正则表达式引擎可以设置为从右到左工作,如果我没记错的话.net可以做到这一点)
如果第一个标记匹配,则正则表达式引擎使用下一个字符测试模式的下一个标记(在第一个令牌匹配之后) etc.
当令牌失败时,正则表达式引擎会获取最后一个令牌匹配的字符,并尝试另一种方法来使模式成功(如果它也不起作用,正则表达式引擎会对之前的标记等执行相同的操作。)
当正则表达式引擎满足(*SKIP)
verb (在这种情况下,所有之前的令牌显然都成功了),它不再有权返回到左侧的所有先前标记,也不再有权使用模式的另一个分支或在字符串中的下一个位置重试所有匹配的字符,直到最后一个匹配的字符(包括)如果该模式稍后在右侧失败(*SKIP)
verb.
的作用(*FAIL)
是迫使模式失败。因此左侧的所有字符都匹配(*SKIP)
被跳过,正则表达式引擎在这些字符之后继续其工作。
在示例模式中,该模式成功的唯一可能性是第一个分支之前失败(*SKIP)
允许测试第二个分支。
你可以找到另一种解释here https://stackoverflow.com/questions/19992984/verbs-that-act-after-backtracking-and-failure/20008790#20008790.
About Java and other regex engines that don't have these two features
回溯控制动词未在其他正则表达式引擎中实现,并且没有等效项。
但是,您可以使用多种方法来完成相同的操作(更清楚地说,是为了避免可能与模式的其他部分匹配的内容).
捕获组的使用:
way 1:
What_I_want_to_avoid|(What_I_want_to_match)
只需要提取捕获组1(或测试它是否存在),因为这就是您正在寻找的东西。如果使用模式进行替换,则可以使用匹配结果的属性(偏移量、长度、捕获组)来使用经典字符串函数进行替换。其他语言如 javascript、ruby...允许使用回调函数作为替代。
way 2:
((?>To_avoid|Other_things_that_can_be_before_what_i_want)*)(What_I_want)
这是更简单的替换方式,不需要回调函数,替换字符串只需要以\1
(or $1
)
环顾四周的使用:
例如,您想要找到一个未嵌入其他两个单词之间的单词(比方说S_word
and E_word
是不同的(参见Qtax评论)):
(边缘情况S_word E_word word E_word
and S_word word S_word E_word
本例中允许。)
回溯控制动词方式将是:
S_word not_S_word_or_E_word E_word(*SKIP)(*F)|word
要使用这种方式,正则表达式引擎需要在一定程度上允许可变长度后视。使用.net或新的正则表达式模块,没有问题,lookbehinds可以具有完全可变的长度。 Java 也可以,但大小必须受到限制(例子:(?<=.{1,1000})
).
Java 等效项将是:
word(?:(?!not_S_word_or_E_word E_word)|(?<!S_word not_E_word{0,1000} word))
请注意,在某些情况下,仅需要前瞻。还要注意,以文字字符开始模式比以后行开始更有效,这就是为什么我把它放在单词后面(即使我需要在断言中再次重写该词。)