我有key=value
对这样的逗号分隔字符串:
foo=1,foo=1,bar=2
在此字符串中,我要捕获 first foo
的值,但前提是紧随其后的是bar=2
。
在此字符串中,应捕获值1
:
baz=0,foo=1,bar=2,foo=3,bar=4
在此字符串中,不应捕获任何内容:
baz=0,foo=1,foo=1,bar=2
我当前的解决方案使用了经过调节的贪婪令牌,但这迫使我复制了正则表达式的foo=[^,]*,
部分:
^(?:(?!foo=[^,]*,).)*foo=([^,]*),bar=2(?:,|$)
有什么方法可以做到而不必复制正则表达式的很大一部分?
答案 0 :(得分:3)
使用backtracking control verbs很简单:
(?<![^,])foo=([^,]*)(*COMMIT),bar=2(?![^,])
我们匹配一个不以非逗号字符开头的位置(例如,字符串的开头或紧接,
之后),然后是foo=
,然后是0个或多个非逗号字符(我们捕获)。这是foo=...
部分。
然后我们提交找到的第一个匹配项,并要求进行,bar=2
匹配,而不是非逗号字符(即,
或字符串的结尾)。
答案 1 :(得分:0)
免责声明:仅在某些正则表达式引擎中有效。
某些正则表达式引擎具有我们可以滥用的“特征”:提前捕获组具有所有格;一旦匹配,就无法再更改其值。
利用此“功能”,可以将正则表达式编写为:
.*?(?!\1)thing_you_want_the_first_occurrence_of(?=())rest_of_the_regex
在这种特定情况下,看起来像这样(由于foo=([^,]*)
包含捕获组,捕获组的索引移动了1):
.*?(?!\2)(?<![^,])foo=([^,]*),(?=())bar=2(?![^,])
那么,它如何工作?
找到foo=
的第一个匹配项后,组(?=())
匹配。因为它位于先行之内,所以它永远无法再更改其值-甚至回溯也不会影响它。因此,从现在开始,(?!\2)
将不再匹配。现在发现“ foo=
的第一次出现这一事实已被“锁定”并且无法撤消。如果正则表达式回溯并尝试使.*?
与更多文本匹配,则(?!\2)
会阻止这种情况。
使用python的PyPI regex
module进行演示:
>>> pattern = r'.*?(?!\2)(?<![^,])foo=([^,]*),(?=())bar=2(?![^,])'
>>> regex.match(pattern, 'baz=0,foo=1,bar=2,foo=3,bar=4').group(1)
'1'
>>> regex.match(pattern, 'baz=0,foo=1,foo=1,bar=2')
>>>