【问题标题】:Regular Expression backtracks until overflow in Java正则表达式回溯直到在 Java 中溢出
【发布时间】:2017-06-23 03:28:48
【问题描述】:

下面的表达式:

^(#ifdef FEATURE)+?\s*$((\r\n.*?)*^(#endif)+\s*[\/\/]*\s*(end of)*\s*FEATURE)+?$

在运行我编译的 .Jar 文件时覆盖匹配的缓冲区。

匹配的字符串可以类似于:

这是一条垃圾线

#ifdef FEATURE
#endif // FEATURE 结束

这是一条垃圾线

#ifdef FEATURE

这是一条应该匹配的垃圾行:HOLasduiqwhei & // FEATURE fjfefj #endif // h

#endif 功能

这是一条垃圾线

因此,粗体字符串应该匹配。错误如下:

   at java.util.regex.Pattern$GroupHead.match(Unknown Source)
   at java.util.regex.Pattern$Loop.match(Unknown Source)
   at java.util.regex.Pattern$GroupTail.match(Unknown Source)
   at java.util.regex.Pattern$Curly.match1(Unknown Source)
   at java.util.regex.Pattern$Curly.match(Unknown Source)
   at java.util.regex.Pattern$Slice.match(Unknown Source)
   at java.util.regex.Pattern$GroupHead.match(Unknown Source)
   at java.util.regex.Pattern$Loop.match(Unknown Source)
   at java.util.regex.Pattern$GroupTail.match(Unknown Source)
   at java.util.regex.Pattern$Curly.match1(Unknown Source)
   at java.util.regex.Pattern$Curly.match(Unknown Source)
   at java.util.regex.Pattern$Slice.match(Unknown Source)
   at java.util.regex.Pattern$GroupHead.match(Unknown Source)
   at java.util.regex.Pattern$Loop.match(Unknown Source)
   at java.util.regex.Pattern$GroupTail.match(Unknown Source)
   at java.util.regex.Pattern$Curly.match1(Unknown Source)
   at java.util.regex.Pattern$Curly.match(Unknown Source)
   at java.util.regex.Pattern$Slice.match(Unknown Source)
   at java.util.regex.Pattern$GroupHead.match(Unknown Source)
   at java.util.regex.Pattern$Loop.match(Unknown Source)
   at java.util.regex.Pattern$GroupTail.match(Unknown Source)
   at java.util.regex.Pattern$Curly.match1(Unknown Source)
   at java.util.regex.Pattern$Curly.match(Unknown Source)
   at java.util.regex.Pattern$Slice.match(Unknown Source)
   at java.util.regex.Pattern$GroupHead.match(Unknown Source)
   at java.util.regex.Pattern$Loop.match(Unknown Source)
   at java.util.regex.Pattern$GroupTail.match(Unknown Source)
   at java.util.regex.Pattern$Curly.match1(Unknown Source)
   at java.util.regex.Pattern$Curly.match(Unknown Source)
   at java.util.regex.Pattern$Slice.match(Unknown Source)

欢迎任何避免策略/改进表达的回溯。我尝试了原子组(?>),但由于某种原因没有简化。

代码如下:

公共字符串条(字符串文本){

    ArrayList<String> patterns=new ArrayList<String>();
    patterns=readFile("Disabled_Features.txt");
    for(int i = 0; i < patterns.size(); ++i)
    {

      Pattern todoPattern = Pattern.compile("^#ifdef "+patterns.get(i)+"((?:\\r?\\n(?!#endif (?:// end of )?"+patterns.get(i)+"$).*)*)\\r?\\n#endif (?:// end of )?"+patterns.get(i)+"$",Pattern.MULTILINE); 

      Matcher m = todoPattern.matcher(text);
      text = m.replaceAll("");
    }
    return text;        
}

【问题讨论】:

  • 检查this regex demo
  • 你好,你的表情还是让我溢出。
  • 请贴出用于匹配正则表达式的代码
  • 对不起,功能块如下:再次查看帖子。
  • erg...我的意思是java代码。我已经更新了我的答案,并尝试了@WiktorStribiżew 编写的代码。没有溢出。

标签: java regex pattern-matching backtracking


【解决方案1】:

我已经尝试过@Wiktor 编写的代码,效果很好

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TestRegex {
  public static void main(String[] args) {
    String text = "this is a junk line\n" + 
        "\n" + 
        "#ifdef FEATURE \n" + 
        "#endif // end of FEATURE\n" + 
        "\n" + 
        "this is a junk line\n" + 
        "\n" + 
        "#ifdef FEATURE\n" + 
        "\n" + 
        "this is a junk line that should be matched: HOLasduiqwhei & // FEATURE fjfefj #endif // h\n" + 
        "\n" + 
        "#endif FEATURE\n" + 
        "\n" + 
        "this is a junk line";

    // this version does not use Pattern.MULTILINE, this should reduce the backtraking
    Matcher matcher2 = Pattern.compile("\\n#ifdef FEATURE((?:\\r?\\n(?!#endif (?:// end of )?FEATURE).*)*)\\r?\\n#endif (?:// end of )?FEATURE").matcher(text);
    while (matcher2.find()) {
      System.out.println(matcher2.group());
    }

  }
}

这让我认为您的问题是由于输入文件的大小造成的。

所以,如果您的文件太大,您可以将输入实现为CharSequence,这样您就可以包装您的大文本文件。为什么?因为从Pattern 构建Matcher 需要CharSequence 作为参数。

https://github.com/fge/largetext

【讨论】:

  • 据我所见,我的表达式没有明显的左括号。就在最后一个'FEATURE'之后。我在快速浏览器编译器中尝试了您的表达式,但不起作用。最后的“FEATURE”名称应为必填项。
  • 您好,这个正则表达式确实应该与块匹配,但是当我在我的 java 文件中使用它时,它只会溢出,并且目标文件没有明显的变化。
  • 可能异常是由你正在解析的文件大小引起的。
  • 有什么解决办法吗?
  • 你能把它贴出来让我试试吗?
【解决方案2】:

更新:

我尝试实现 Wiktor 的解决方案:

"^#ifdef "+patterns.get(i)+"((?:\\r?\\n(?!#endif (?:// end of )?"+patterns.get(i)+"$).*)*)\\r?\\n#endif (?:// end of )?"+patterns.get(i)+"$"

它只捕获第二个块,而不是以下一个:

#ifdef FEATURE

垃圾捕获文本

#endif // FEATURE 结束

无论如何,当我运行 jar 时仍然会溢出。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-06
    • 1970-01-01
    • 1970-01-01
    • 2013-08-09
    • 2017-08-23
    • 1970-01-01
    相关资源
    最近更新 更多