zx8*_*x81 9 regex recursion quantifiers
首先,让我解释一下,这个问题既不是关于如何捕获组,也不是关于如何使用量词,这是我非常熟悉的正则表达式的两个特征.对于可能熟悉异国情调引擎中不寻常语法的正则表达式爱好者而言,这是一个更高级的问题.
捕捉量词
有谁知道正则表达式的味道是否允许你捕捉量词?通过这个,我的意思是计数与+和*等量词匹配的字符数将被计算,并且这个数字可以在另一个量词中再次使用.
例如,假设您要确保在此类字符串中具有相同数量的Ls和Rs:LLLRRRRR
你可以想象一下这样的语法
L(+)R{\q1}
Run Code Online (Sandbox Code Playgroud)
其中捕获了L的+量词,并且在R的量词中将捕获的数字称为{\ q1}
这对平衡{@,=, - ,/}在字符串中的数量很有用,例如@@@@"星球大战"===="1977"----"科幻小说"////"乔治卢卡斯"
与递归的关系
在某些情况下,量词捕获会优雅地替换递归,例如由相同数量的Ls和Rs构成的一段文本,a in
L(+) some_content R{\q1}
Run Code Online (Sandbox Code Playgroud)
这个想法在下面的页面中有一些细节:Captifured Quantifiers
它还讨论了捕获量化的自然扩展:量化算术,适用于您希望匹配(3*x + 1)之前匹配的字符数的情况.
我试图找出这样的事情是否存在.
在此先感谢您的见解!
更新
Casimir给出了一个很棒的答案,它显示了两种方法来验证模式的各个部分具有相同的长度.但是,我不想在日常工作中依赖其中任何一种.这些都是表现出色表演的伎俩.在我看来,这些美丽但复杂的方法证实了这个问题的前提:一个正则表达式特征来捕获量化的字符数(例如+或*)能够匹配将使这种平衡模式非常简单并扩展语法一种令人愉快的表达方式.
更新2(稍后)
我发现.NET有一个接近我所询问的功能.添加了演示该功能的答案.
Cas*_*yte 12
我不知道可以捕获量词的正则表达式引擎.但是,使用PCRE或Perl可以使用一些技巧来检查您是否具有相同数量的字符.用你的例子:
@@@@ "Star Wars" ==== "1977" ---- "Science Fiction" //// "George Lucas"
@ = - /这种使用着名的Qtax技巧的模式是否平衡,(你准备好了吗?):"所有权 - 可选的自引用组"
~(?<!@)((?:@(?=[^=]*(\2?+=)[^-]*(\3?+-)[^/]*(\4?+/)))+)(?!@)(?=[^=]*\2(?!=)[^-]*\3(?!-)[^/]*\4(?!/))~
Run Code Online (Sandbox Code Playgroud)
图案细节:
~ # pattern delimiter
(?<!@) # negative lookbehind used as an @ boundary
( # first capturing group for the @
(?:
@ # one @
(?= # checks that each @ is followed by the same number
# of = - /
[^=]* # all that is not an =
(\2?+=) # The possessive optional self-referencing group:
# capture group 2: backreference to itself + one =
[^-]*(\3?+-) # the same for -
[^/]*(\4?+/) # the same for /
) # close the lookahead
)+ # close the non-capturing group and repeat
) # close the first capturing group
(?!@) # negative lookahead used as an @ boundary too.
# this checks the boundaries for all groups
(?=[^=]*\2(?!=)[^-]*\3(?!-)[^/]*\4(?!/))
~
Run Code Online (Sandbox Code Playgroud)
主要想法
非捕获组仅包含一个@.每次重复该组时,在捕获组2,3和4中添加新字符.
占有 - 可选的自我引用组
它是如何工作的?
( (?: @ (?= [^=]* (\2?+ = ) .....) )+ )
Run Code Online (Sandbox Code Playgroud)
在第一次出现@字符时,捕获组2尚未定义,因此您无法编写类似于(\2 =)使模式失败的内容.为了避免这个问题,方法是使反向引用可选:\2?
该组的第二方面=是在非捕获组的每次重复时增加匹配的字符数,因为=每次都添加a.为确保此数字始终增加(或模式失败),占有量词强制在添加新=字符之前首先匹配反向引用.
请注意,可以看到这样的组:如果组2存在,则将其与下一组匹配=
( (?(2)\2) = )
Run Code Online (Sandbox Code Playgroud)
~(?<!@)(?=(@(?>[^@=]+|(?-1))*=)(?!=))(?=(@(?>[^@-]+|(?-1))*-)(?!-))(?=(@(?>[^@/]+|(?-1))*/)(?!/))~
Run Code Online (Sandbox Code Playgroud)
你需要使用重叠匹配,因为你将多次使用@部分,这就是为什么所有模式都在里面看起来的原因.
图案细节:
(?<!@) # left @ boundary
(?= # open a lookahead (to allow overlapped matches)
( # open a capturing group
@
(?> # open an atomic group
[^@=]+ # all that is not an @ or an =, one or more times
| # OR
(?-1) # recursion: the last defined capturing group (the current here)
)* # repeat zero or more the atomic group
= #
) # close the capture group
(?!=) # checks the = boundary
) # close the lookahead
(?=(@(?>[^@-]+|(?-1))*-)(?!-)) # the same for -
(?=(@(?>[^@/]+|(?-1))*/)(?!/)) # the same for /
Run Code Online (Sandbox Code Playgroud)
与先例模式的主要区别在于,这个模式并不关心组= -和/组的顺序.(但是你可以轻松地对第一个模式进行一些更改来处理它,包括字符类和负向前瞻.)
注意:对于示例字符串,更具体地说,您可以使用锚点(^或\A)替换负向lookbehind .如果你想获得整个字符串作为匹配结果,你必须.*在最后添加(否则匹配结果将为空,因为俏皮注意到它.)