2013-05-16 91 views
16

我敢肯定,我失去了一些东西很明显这里,但我不能让R来使用非贪婪的正则表达式:非贪婪字符串正则表达式匹配

> library(stringr) 
> str_match('xxx aaaab yyy', "a.*?b")           
    [,1] 
[1,] "aaaab" 

基本功能相同的行为方式:

> regexpr('a.*?b', 'xxx aaaab yyy') 
[1] 5 
attr(,"match.length") 
[1] 5 
attr(,"useBytes") 
[1] TRUE 

我希望这场比赛是按照 '贪婪' 的评论中http://stat.ethz.ch/R-manual/R-devel/library/base/html/regex.html只是ab

默认情况下,重复是贪婪的,所以使用最大可能的重复次数。 这可以通过追加更改为'最小'?给量词。 (还有更多 量词允许近似匹配:请参阅TRE文档。)

请问有人能解释我发生了什么事吗?

更新。什么是疯狂的是,在其他一些情况下,非贪婪模式像预期的那样:

> str_match('xxx <a href="abc">link</a> yyy <h1>Header</h1>', '<a.*>') 
    [,1]           
[1,] "<a href=\"abc\">link</a> yyy <h1>Header</h1>" 
> str_match('xxx <a href="abc">link</a> yyy <h1>Header</h1>', '<a.*?>') 
    [,1]    
[1,] "<a href=\"abc\">" 

回答

18

难以理解的概念,所以我会尽我所能...有人随意编辑和更好的解释,如果它是一个有点混乱。

匹配您的模式的表达式从左到右搜索。是的,以下所有字符串aaaab,aaab,aabab都与您的模式相匹配,但aaaab是最左边最开始的字符串是返回的字符串。

所以在这里,你的非贪婪模式不是很有用。也许这其他例子可以帮助您更好地了解当一个非贪婪模式踢:

str_match('xxx aaaab yyy', "a.*?y") 
#  [,1]  
# [1,] "aaaab y" 

这里所有字符串aaaab yaaaab yyaaaab yyy匹配的模式,并在同一位置开始,但第一个是由于非贪婪模式返回。


那么你能做些什么来捕获最后的ab?使用这个:

str_match('xxx aaaab yyy', ".*(a.*b)") 
#  [,1]  [,2] 
# [1,] "xxx aaaab" "ab" 

它是如何工作的?通过在前面添加贪婪模式.*,您现在正在强制该过程将最后一个可能的a放入捕获的组中。

+0

谢谢@ floder - 我完全忘了它总是从左边开始匹配。人们正在长时间讨论它:http://www.nntp.perl.org/group/perl.perl6.language.regex/2000/12/msg507.html –

3

问题匹配两个字符串之间的最短窗口。 @ flodel正确地提到了正则表达式引擎正在从左向右解析字符串,因此所有匹配项都是最左边的。贪婪和懒惰只适用于右边的边界:贪婪的量词使得子字符串达到最右边的边界,而懒惰的字符将匹配第一次出现的子模式。

参见例子

> library(stringr) 
> str_extract('xxx aaaab yyy', "a[^ab]*b") 
[1] "ab" 
> str_extract('xxx aaa xxx aaa zzz', "xxx.*?zzz") 
[1] "xxx aaa xxx aaa zzz" 
> str_extract('xxx aaa xxx aaa zzz', "xxx(?:(?!xxx|zzz).)*zzz") 
[1] "xxx aaa zzz" 

第一和第三情景返回最短窗口,第二个是当前的问题,但具有一个多字符输入的说明图。

方案1.边界是单个字符

在壳体ab是单个字符,最短窗口是通过使用否定的字符类中找到。 a[^ab]*b将很容易地从a获取子字符串,直到下一个b,其间没有a s和b s。

场景2.边界不是单个字符

您可以在这些情况下,可以进一步展开使用tempered greedy token。所述xxx(?:(?!xxx|zzz).)*zzz模式匹配xxx,然后比断行字符不是一个xxxzzz炭序列的起始字符以外的任何字符0+(所述(?!xxx|zzz)负先行失败比赛如果立即子串向右比赛向前的模式),然后是zzz

> x <- 'xxx aaa xxx aaa zzz xxx bbb xxx ccc zzz' 
> unlist(regmatches(x, gregexpr("xxx(?:(?!xxx|zzz).)*zzz", x, perl = TRUE))) 
[1] "xxx aaa zzz" "xxx ccc zzz" 

一个注意:使用在基R A PCRE正则表达式的情况下,或在ICU

这些匹配场景可以与基础R regmatches(使用支持向前看符号一个PCRE正则表达式的香味)很容易地使用正则表达式str_extract/str_match.与换行符不匹配,要启用该行为,需要在模式开始处添加(?s)(内联DOTALL修饰符)。