回溯中的反向引用

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,所以我不能自己尝试 - 如果反向引用组在环视之外会发生什么,例如 (?&lt;=\\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 中已修复。

以上是关于回溯中的反向引用的主要内容,如果未能解决你的问题,请参考以下文章

EntityFramework - 数据库中的多对多引用,模型中没有反向引用

替换字符串中的反向引用语法(为啥是美元符号?)

Java中的正则表达式反向引用

TCL 中的反向引用有问题

IntelliJ 中的正则表达式反向引用

backreference Oracle正則表達式中的反向引用