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

Vic*_* K. 23 regex r stringr

我很确定我在这里遗漏了一些明显的东西,但是我不能让R使用非贪婪的正则表达式:

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

基本函数的行为方式相同:

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

我希望这场比赛符合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\">"
Run Code Online (Sandbox Code Playgroud)

flo*_*del 24

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

从左到右搜索与您的模式匹配的表达式.是的,所有的下列字符串aaaab,aaab,aab,和ab对你的模式匹配,但aaaab作为启动最给左边的一个是返回的一个.

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

str_match('xxx aaaab yyy', "a.*?y") 
#      [,1]     
# [1,] "aaaab y"
Run Code Online (Sandbox Code Playgroud)

这里所有的琴弦aaaab y,aaaab yy,aaaab yyy匹配的模式,并在同一位置开始,但第一个是因为非贪婪模式的返回.


那么你能做些什么才能抓住最后一个ab呢?用这个:

str_match('xxx aaaab yyy', ".*(a.*b)")
#      [,1]        [,2]
# [1,] "xxx aaaab" "ab"
Run Code Online (Sandbox Code Playgroud)

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


Wik*_*żew 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"
Run Code Online (Sandbox Code Playgroud)

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

场景1.边界是单个字符

在壳体ab是单个字符,最短窗口是通过使用否定的字符类中找到.a[^ab]*b很容易抓住子串a直到下一个b没有as和bs之间.

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

在这些可以进一步展开的情况下,您可以使用淬火贪婪令牌.的xxx(?:(?!xxx|zzz).)*zzz模式相匹配xxx,则比断行字符不是一个起始字符以外的任何字符0+ xxxzzz字符序列((?!xxx|zzz)负先行失败比赛,如果子立即向右先行图案匹配),然后a zzz.

这些匹配方案可以很容易地与base R一起regmatches使用(使用支持前瞻的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"
Run Code Online (Sandbox Code Playgroud)

一注:使用基础R一个PCRE正则表达式,或在ICU正则表达式时str_extract/ str_match时,.不匹配换行符字符,以使这种行为,你需要添加(?s)在模式开始(内嵌DOTALL修饰符).