非贪婪的字符串正则表达式匹配

时间:2013-05-16 01:03:54

标签: regex r stringr

我很确定我在这里遗漏了一些明显的东西,但我不能让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

  

默认情况下,重复是贪婪的,因此使用最大可能的重复次数。       这可以通过附加改为'minimal'吗?到量词。 (还有更多       允许近似匹配的量词:参见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\">"

2 个答案:

答案 0 :(得分:24)

困难的概念所以我会尽我所能......如果有点混乱,有人可以自由编辑和解释。

从左到右搜索与您的模式匹配的表达式。是的,以下所有字符串aaaabaaabaabab都与您的模式匹配,但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放入捕获的组中。

答案 1 :(得分:6)

问题匹配两个字符串之间的最短窗口。 @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,其间没有ab

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

在这些可以进一步展开的情况下,您可以使用tempered greedy tokenxxx(?:(?!xxx|zzz).)*zzz模式匹配xxx,然后匹配除了不是xxxzzz char序列的起始字符的换行符之外的任何0+字符({{1如果右边的子字符串与前瞻模式匹配,那么否定前瞻会使匹配失败,然后是(?!xxx|zzz)

这些匹配的方案可以很容易地与基础R zzz一起使用(使用支持前瞻的PCRE正则表达式):

regmatches

一个注意事项:在基础R中使用PCRE正则表达式,或在> 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" / str_extract中使用ICU正则表达式时,str_match与换行符不匹配,以启用该行为,需要在模式开始处添加.(内联DOTALL修饰符)。