(* SKIP)或(* F)如何在正则expression式上工作?
我正在学习正则expression式的高级用法,并注意到许多post都使用(*SKIP)
或(*F)
。
我发布了一个问题,其中的想法是匹配没有yellow
但只有在蓝色之后存在brown
蓝色的行。 正确的答案是:
.*yellow.*(*SKIP)(*F)|^.*\bblue\b(?=.*brown).*$
我也试过像下面这样的查找expression式,但并没有为所有的情况工作:
^((?!yellow).)*blue(?=.*brown).*$
我不知道这些(*SKIP)(*F)
标志,所以问题是,这些标志是如何工作的? 他们在做什么? 还有其他像这样的标志吗?
谢谢。
这两个回溯控制动词只在Perl,PCRE和pypi regex模块中实现 。
(*SKIP)(*FAIL)
技巧的想法是消耗你想要避免的字符,而且不能是匹配结果的一部分。
使用这种技巧的古典模式如下所示:
What_I_want_to_avoid(*SKIP)(*FAIL)|What_I_want_to_match
正则expression式引擎处理这样一个string:
-
模式的第一个标记从左到右testing每个字符(默认情况下,大部分时间,但一些正则expression式引擎可以设置为从右到左工作,.net可以做到这一点,如果我没记错的话)
-
如果第一个标记匹配,那么正则expression式引擎会testing下一个字符(在第一个标记匹配之后)的下一个标记 。
-
当一个令牌失败时,正则expression式引擎获取最后一个令牌匹配的字符,并尝试另一种方式使得该模式成功(如果它不工作,则正则expression式引擎也会和前一个令牌一样)
当正则expression式引擎遇到(*SKIP)
动词时(在这种情况下,所有以前的令牌显然成功了) ,它没有权利回到所有先前的令牌,并且没有权利重试所有的如果模式在(*SKIP)
动词右侧后面失败,则直到最后一个匹配的字符(包含) 。
(*FAIL)
的作用是强制模式失败。 因此,在(*SKIP)
左边匹配的所有字符都被跳过,正则expression式引擎在这些字符之后继续工作。
在示例模式中,模式成功的唯一可能性是第一个分支在(*SKIP)
之前失败,以允许testing第二个分支。
你可以在这里find另一种解释。
关于没有这两个function的 Java 和其他正则expression式引擎
其他正则expression式引擎中没有实现回溯控制动词,并且没有等价物。
然而,你可以用几种方法来做同样的事情(要更清楚一些,以避免可能被模式的其他部分匹配的东西) 。
捕获组的使用:
方式1:
What_I_want_to_avoid|(What_I_want_to_match)
您只需要提取捕获组1 (或者testing它是否存在) ,因为这是您正在查找的内容。 如果使用该模式执行replace,则可以使用匹配结果(偏移量,长度,捕获组)的属性使用经典string函数进行replace。 其他语言如JavaScript,ruby…允许使用callback函数作为替代。
方式2:
((?>To_avoid|Other_things_that_can_be_before_what_i_want)*)(What_I_want)
这是更换简单的方法,不需要callback函数,replacestring只需要以\1
(或$1
)开始,
lookarounds的使用:
例如,你想find一个没有embedded其他两个单词之间的单词(可以说S_word
和E_word
是不同的(参见Qtax评论) ):
(在这个例子中边缘情况S_word E_word word E_word
和S_word word S_word E_word
是允许的。)
回溯控制动词的方式是:
S_word not_S_word_or_E_word E_word(*SKIP)(*F)|word
为了使用这种方式,正则expression式引擎需要在一定程度上允许可变长度的lookbehinds。 使用.net或新的正则expression式模块,没有问题,lookbehinds可以有一个完全可变的长度。 Java也可以,但是大小必须是有限的(例如: (?<=.{1,1000})
) 。
Java的等价物将是:
word(?:(?!not_S_word_or_E_word E_word)|(?<!S_word not_E_word{0,1000} word))
请注意,在某些情况下,只有前瞻是必要的。 还要注意,用字面字符开始一个模式比从一个逆序开始更有效率,这就是为什么我把它放在单词之后(即使我需要在断言中再次重写单词)。
(*SKIP)
和(*F)
(aka *FAIL
)模式logging在Perl手册中: http : //perldoc.perl.org/perlre.html
但是,它们只能用于Perl以及模仿Perl的正则expression式(例如PHP使用的PCRE库)。
Java的内置正则expression式引擎不支持这些扩展,我不知道这样做。
我在Java中的一般build议是保持你的正则expression式简单,并使用其他的string操作方法来实现一个简短的正则expression式无法完成的事情。