【问题标题】:Java regex look-behind group does not have obvious maximum length errorJava regex look-behind group 没有明显的最大长度错误
【发布时间】:2014-09-12 12:11:08
【问题描述】:

我知道 java regex 不支持可变长度的后视,以下应该会导致错误

(?<=(not exceeding|no((\\w|\\s)*)more than))xxxx

但是当 * 被替换为固定长度的说明符时

(?<=(not exceeding|no((\\w|\\s){0,30})more than))xxxx

它仍然失败。这是为什么呢?

【问题讨论】:

  • 您尝试过的确切正则表达式是什么。你上面提到的那个?
  • Lookbehinds 必须是零宽度,因此不允许使用量词
  • @Swapnil 为了简单起见,我删除了后面的一些关键字,xxxx 是更长表达式的占位符,但我已经测试了那部分,这不是问题跨度>
  • 查看here

标签: java regex


【解决方案1】:

Java Lookbehind 臭名昭著

所以你认为 Java 不支持无限后视?

但是下面的模式会编译!

(?<=\d+)\w+

...尽管在 Match All 中会产生意想不到的结果(请参阅demo)。

另一方面,你可以成功地使用这个无限的后视(我在this question 上发现了非常惊讶的)

(?<=\\G\\d+,\\d+,\\d+),

拆分此字符串:0,123,45,6789,4,5,3,4,6000

它会正确输出(见online demo):

0,123,45
6789,4,5
3,4,6000

这一次的结果是你所期望的。

但是,如果您使用(?&lt;=\\G\\d+,\\d+), 稍微调整正则表达式以获得对而不是三元组,这一次它不会分裂(请参阅the demo)。


底线

Java lookbehind 是出了名的错误。知道这一点,我推荐你 不要浪费时间试图理解它为什么会这样做 没有记录。

前段时间让我得出这个结论的决定性的话是 Jan Goyvaerts 的话,他是 The Regex Cookbook 的合著者,也是一位创造了一个了不起的正则表达式大师正则表达式引擎,并且需要在他的调试工具 RegexBuddy 中掌握大多数正则表达式风格:

Java 在其lookbehind 实现中存在许多错误。一些(但 并非所有)这些都在 Java 6 中得到修复。

【讨论】:

  • 我决定赏金给你的理由是:“不要浪费时间试图理解错误”。虽然有趣的是出了什么问题,但如果您已经有可行的替代解决方案,则不值得花太多时间来解决问题。
  • @Pshemo 谢谢你的赏金。前段时间我走上了同样的路,向 JG 询问了惊人的 JS 后视行为,得出了和你一样的结论......最后,如果它有 bug,我们该怎么办?
【解决方案2】:

java 正则表达式不支持变长的look-behinds

这并不完全正确,Java 支持有限的可变长度后视,例如(?&lt;=.{0,1000}) 是允许的,或者类似(?&lt;=ab?)c(?&lt;=abc|defgh)

但如果完全没有限制,Java 是不支持的。

那么,对于 Java 正则表达式引擎,对于后向子模式来说,什么是不明显的:

{m,n} 量词应用于非固定长度子模式:

(?:abc){0,1} is allowed

(?:ab?)?     is allowed
(?:ab|de)    is allowed
(?:ab|de)?   is allowed

(?:ab?){0,1}   is not allowed
(?:ab|de){1}   is not allowed
(?:ab|de){0,1} is not allowed # in my opinion, it is because of the alternation.
                              # When an alternation is detected, the analysis
                              # stops immediatly

要在这种特殊情况下获得此错误消息,您需要两个条件:

  • 一个潜在的可变长度子模式(即:包含量词、替代或反向引用)

  • 和一个{m,n} 类型量词。

所有这些情况对用户来说似乎并不明显,因为这似乎是一个任意选择。但是,我认为真正的原因是通过正则表达式引擎传输来限制模式的预分析时间。

【讨论】:

  • 这对我来说是正确的答案。我只是将后面的“+”更改为“{1,100}”之类的内容,一切都按预期工作。
【解决方案3】:

这确实很奇怪。我没有找到解释,但如果您将(\\w|\\s){0,30} 更改为[\\w\\s]{0,30},问题似乎消失了

Pattern.compile("(?<=(not exceeding|no([\\w\\s]{0,30})more than))xxxx");
//BTW you don't need ^-----------------------------------------^ these parenthesis
//unless you want to use match from this group later

【讨论】:

  • 根据 OP,两者都失败了。我认为这两种方式都是可变长度的。
  • 这也适用于我。奇怪的。我以前在这个确切的上下文中使用过括号很多次,它从来没有失败过,但是这个似乎需要括号
  • @user2559503 Java 中的 Look-behind 确实是个奇怪的生物。有时即使很明显(例如在这种情况下)它也无法计算出最大长度,有时它允许使用无限的正则表达式(例如在this answer 中)。
  • "除非你以后想从这个组中匹配" 如果无论如何都在一个组后面,你肯定不需要那些额外的括号。还没有测试过...
【解决方案4】:

以下是一些测试用例(如@Pshemo 所述,我删除了多余的括号)。它仅在后视包含 sub-alternation 的情况下失败。错误是

Look-behind group does not have an obvious maximum length near index 45

“明显”是这里的关键词。

   import  java.util.regex.Pattern;
public class Test  {
   public static final void main(String[] ignored)  {
      test("(?<=not exceeding|no)xxxx");
      test("(?<=not exceeding|NOT EXCEEDING)xxxx");
      test("(?<=not exceeding|x{13})xxxx");
      test("(?<=not exceeding|x{12}x)xxxx");
      test("(?<=not exceeding|(x|y){12}x)xxxx");
      test("(?<=not exceeding|no(\\w|\\s){2,30}more than)xxxx");
      test("(?<=not exceeding|no(\\w|\\s){0,2}more than)xxxx");
      test("(?<=not exceeding|no(\\w|\\s){2}more than)xxxx");
   }
      private static final void test(String regex)  {
         System.out.print("testing \"" + regex + "\"...");
         try  {
            Pattern p = Pattern.compile(regex);
            System.out.println("Success");
         }  catch(Exception x)  {
            System.out.println(x);
         }

      }
}

输出:

testing "(?<=not exceeding|no)xxxx"...Success
testing "(?<=not exceeding|NOT EXCEEDING)xxxx"...Success
testing "(?<=not exceeding|x{13})xxxx"...Success
testing "(?<=not exceeding|x{12}x)xxxx"...Success
testing "(?<=not exceeding|(x|y){12}x)xxxx"...java.util.regex.PatternSyntaxException: Look-behind group does not
 have an obvious maximum length near index 27
(?<=not exceeding|(x|y){12}x)xxxx
                           ^
testing "(?<=not exceeding|no(\w|\s){2,30}more than)xxxx"...java.util.regex.PatternSyntaxException: Look-behind
group does not have an obvious maximum length near index 41
(?<=not exceeding|no(\w|\s){2,30}more than)xxxx
                                         ^
testing "(?<=not exceeding|no(\w|\s){0,2}more than)xxxx"...java.util.regex.PatternSyntaxException: Look-behind g
roup does not have an obvious maximum length near index 40
(?<=not exceeding|no(\w|\s){0,2}more than)xxxx
                                        ^
testing "(?<=not exceeding|no(\w|\s){2}more than)xxxx"...java.util.regex.PatternSyntaxException: Look-behind gro
up does not have an obvious maximum length near index 38
(?<=not exceeding|no(\w|\s){2}more than)xxxx
                                      ^

【讨论】:

    猜你喜欢
    • 2023-03-03
    • 2020-02-07
    • 1970-01-01
    • 2011-02-12
    • 2011-02-06
    • 2011-09-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-04
    相关资源
    最近更新 更多