非reedy字符串正则表达式匹配

2024-06-28 20:26:43 发布

您现在位置:Python中文网/ 问答频道 /正文

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

By default repetition is greedy, so the maximal possible number of repeats is used. This can be changed to ‘minimal’ by appending ? to the quantifier. (There are further quantifiers that allow approximate matching: see the TRE documentation.)

有人能解释一下发生了什么事吗

更新。疯狂的是,在其他一些情况下,非贪婪模式的行为与预期一致:

> 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\">"

Tags: theishtmlmatchlibrarylinkh1xxx
2条回答

困难的概念,所以我会尽我最大的努力。。。如果有点混乱,有人可以随意编辑和解释

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

问题是匹配两个字符串之间的最短窗口@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 token来进一步展开。xxx(?:(?!xxx|zzz).)*zzz模式匹配xxx,然后任何0+字符(不是xxxzzz字符序列的起始字符的换行符字符除外)匹配(?!xxx|zzz)是一个负前瞻,如果右边的子字符串与前瞻模式匹配,则匹配失败),然后是一个zzz

这些匹配场景可以很容易地与基本Rregmatches(使用支持lookaheads的PCRE regex风格)一起使用:

> 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"

注意:当在base R中使用PCRE正则表达式或在str_extract/str_match中使用ICU正则表达式时,.与换行符不匹配,要启用该行为,需要在模式开始处添加(?s)(内联DOTALL修饰符)

相关问题 更多 >