回溯中的反向引用
Posted
技术标签:
【中文标题】回溯中的反向引用【英文标题】:Backreferences in lookbehind 【发布时间】:2011-02-13 15:59:51 【问题描述】:你可以在后面使用反向引用吗?
假设我想split
在我身后的任何地方重复两次。
String REGEX1 = "(?<=(.)\\1)"; // DOESN'T WORK!
String REGEX2 = "(?<=(?=(.)\\1)..)"; // WORKS!
System.out.println(java.util.Arrays.toString(
"Bazooka killed the poor aardvark (yummy!)"
.split(REGEX2)
)); // prints "[Bazoo, ka kill, ed the poo, r aa, rdvark (yumm, y!)]"
使用REGEX2
(其中反向引用位于lookahead 中嵌套在lookbehind 中)可以工作,但REGEX1
在运行时会出现此错误:
Look-behind group does not have an obvious maximum length near index 8
(?<=(.)\1)
^
我认为这种有点是有道理的,因为通常反向引用可以捕获任意长度的字符串(不过,如果正则表达式编译器更聪明一点,它可以确定\1
在这种情况下是(.)
,因此长度有限)。
那么有没有办法在回溯中使用反向引用?
如果没有,您是否可以始终使用这种嵌套的前瞻来解决它?还有其他常用的技术吗?
【问题讨论】:
很有趣,并且为您的巧妙解决方法 +1。我不使用 Java,所以我不能自己尝试 - 如果反向引用组在环视之外会发生什么,例如(?<=\\1)(.)
?
@Tim:它产生基本相同的PatternSyntaxException
。顺便说一句,如果有人想解决这个问题的变体,我刚刚在 codingBat 上写了一个:codingbat.com/prob/p266235
@polygenelubricants 我希望我能支持这个正则表达式: (?
【参考方案1】:
看起来你的怀疑是正确的,反向引用通常不能在 Java 后向中使用。您提出的解决方法使后视的有限长度变得明确,对我来说看起来非常聪明。
我很想知道 Python 对这个正则表达式做了什么。 Python只支持固定长度的lookbehind,不像Java那样支持有限长度,但是这个正则表达式是固定长度的。我不能直接使用re.split()
,因为Python 的re.split()
永远不会在空匹配时分裂,但我想我在re.sub()
中发现了一个错误:
>>> r=re.compile("(?<=(.)\\1)")
>>> a=re.sub(r,"|", "Bazooka killed the poor aardvark (yummy!)")
>>> a
'Bazo|oka kil|led the po|or a|ardvark (yum|my!)'
后向匹配在两个重复字符之间!
【讨论】:
查看***.com/questions/2628534/… 以获得更多正则表达式的乐趣。 不过,re.split()
不会在空匹配时拆分,这太愚蠢了。为什么他们会那样做?我认为很多时候您只想根据断言而不是实际的非空分隔符进行拆分。
我在 Python bugtracker 上问过同样的问题。这可能是无意的,但为了不引起兼容性问题而单独放置;正在对正则表达式引擎进行大修,但可能需要一段时间才能将新的正则表达式模块合并到标准库中。
Java 的 regex 包原来也有同样的 bug,lookbehinds 没有锚定在当前匹配位置,但在 JDK 1.6 中已修复。以上是关于回溯中的反向引用的主要内容,如果未能解决你的问题,请参考以下文章