【问题标题】:StackOverflowError in regular expression正则表达式中的 StackOverflowError
【发布时间】:2023-03-18 22:29:01
【问题描述】:

我正在使用正则表达式从多个文档中提取一些字符串。我被这个针对特定正则表达式的“StackOverflowError”卡住了。不使用该正则表达式,程序可以顺利执行。

我的代码:

 package com.gauge.ie.Annotator;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.print.attribute.Size2DSyntax;

import org.apache.commons.io.FilenameUtils;
import org.apache.uima.util.FileUtils;


public class RecursiveFileDisplay 
{

    static List<String> misclist=new ArrayList<String>();
    static List<String> list=new ArrayList<String>();
    static LinkedHashMap<String,String> authormap=new LinkedHashMap<>();
    static List<String> random=new ArrayList<String>();
    static List<String> benchlist=new ArrayList<String>();
    static LinkedHashMap<String,String> benchmap=new LinkedHashMap<>();
    static List<String> misc1list=new ArrayList<String>();
    String csvfile="/home/gauge/Documents/Docs/madras.csv";



    FileWriter fw;

    public RecursiveFileDisplay()throws IOException 
    {
        fw=new FileWriter("/home/gauge/Documents/Docs/supremecourt.csv",true);
        // TODO Auto-generated constructor stub
    }

    public static void main(String[] args) throws Exception
    {
        RecursiveFileDisplay rsd=new RecursiveFileDisplay();
        File currentDir = new File("/home/gauge/Documents/Docs/SampleData/SupremeCourt"); 
        rsd.readFilesFromDirectory(currentDir);
        System.out.println(benchlist.size());
        System.out.println(list.size());
        System.out.println(random.size());
        rsd.writeCSV();
    }
    public void writeCSV()throws IOException 
    {

        for(String str:list)
        {
            fw.append(str);
            fw.append("\n");
            fw.flush();
        }
        System.out.println("Csv file is done!");

    }
    public  void readFilesFromDirectory(File dir) 
    {
        try
        {
            int i=0;
            Pattern p1=Pattern.compile("(Author):(.*)");
            Pattern p=Pattern.compile("(Bench:)(.*)");
            Pattern p2=Pattern.compile("JUDGMENT(.*?)J[.]");
            Pattern p3=Pattern.compile("(([H|h]on)|(HON)).*((ble)|BLE)(.*)");
            //Pattern p4=Pattern.compile(",\\s*([^,]+),[^,]*\\b(J|JJ)\\.");//\s\w*(?=\w*[,]\sJ[.]*\b)
            Pattern p5=Pattern.compile("\\s\\w*(?=\\w*[,]\\sJ[.]*\\b)");
            Pattern p4=Pattern.compile("\\w*(?=\\w*[,]*\\s*((JJ)|(L.J)|(C.J)|(J))[.]\\s\\b)");
            Pattern p6=Pattern.compile("(BENCH:)((.|\\n)*)(BENCH)((.|\\n)*)(CITATION)");
            File[] listfiles=dir.listFiles();
            for(File file:listfiles)
            {
                if(file.isFile())
                {
                String str="";
                String line="";
                BufferedReader br=new BufferedReader(new FileReader(file));
                while((line=br.readLine())!=null)
                {
                    str+=line+"\n";
                }
                Matcher match=p.matcher(str);
                Matcher match1=p1.matcher(str);
                Matcher match2=p2.matcher(str);
                Matcher match3=p3.matcher(str);
                Matcher match4=p4.matcher(str);
                Matcher match5=p5.matcher(str); 
                Matcher match6=p6.matcher(str);

                 if(match.find())
                 {
                    if(match1.find())
                    {
                        list.add(file.toString()+"\t"+match.group(2)+"\t"+match1.group(2));         //filename,   judgename    ,authorname
                        System.out.println(match1.group(2));
                    }
                    else
                    {
                        list.add(file.toString()+"\t"+match.group(2)+"\t"+" ");
                        System.out.println(match.group(2));
                    }
                 }
                 else if(match1.find())
                 {
                        list.add(file.toString()+"\t"+" "+"\t"+match1.group(2));
                 }
                 else if(match2.find())
                 {
                     list.add(file.toString()+"\t"+match2.group()+"\t"+" ");
                 }
                 else if(match3.find())
                 {
                     list.add(file.toString()+"\t"+match3.group()+"\t"+" ");
                 }
                 else if(match4.find())
                 {
                    //do nothing
                 }
                 else if(match5.find())
                 {
                     list.add(file.toString()+"\t"+match5.group()+"\t"+" ");
                     System.out.println(file.toString());
                 }
                 else if(match6.find())
                 { 
                     System.out.println("lalalalal");
                 }
                 else
                 {
                        misclist.add(file.toString());                          //list of documents which have no Judgenames
                        String name = UUID.randomUUID().toString();
                        PrintWriter pw=new PrintWriter("/home/gauge/Documents/Docs/Misc"+"/"+name);
                        pw.write(str);
                        pw.flush();
                 }

                }
                else if(file.isDirectory())
                {
                    readFilesFromDirectory(file.getAbsoluteFile());
                    System.out.println("recursion");
                }
            }   
        }   
        catch(StackOverflowError soe)
        {
            soe.printStackTrace();
            System.err.print(soe);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            System.err.print(e);
        }
    }

}

当我删除模式 p6 时,它不会显示任何错误。

stackTrace如下:

at java.util.regex.Pattern$GroupTail.match(Pattern.java:4717)
    at java.util.regex.Pattern$BranchConn.match(Pattern.java:4568)
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3777)
    at java.util.regex.Pattern$Branch.match(Pattern.java:4604)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4658)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4785)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4717)
    at java.util.regex.Pattern$BranchConn.match(Pattern.java:4568)
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3777)
    at java.util.regex.Pattern$Branch.match(Pattern.java:4604)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4658)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4785)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4717)
    at java.util.regex.Pattern$BranchConn.match(Pattern.java:4568)
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3777)
    at java.util.regex.Pattern$Branch.match(Pattern.java:4604)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4658)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4785)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4717)
    at java.util.regex.Pattern$BranchConn.match(Pattern.java:4568)
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3777)
    at java.util.regex.Pattern$Branch.match(Pattern.java:4604)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4658)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4785)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4717)
    at java.util.regex.Pattern$BranchConn.match(Pattern.java:4568)
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3777)
    at java.util.regex.Pattern$Branch.match(Pattern.java:4604)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4658)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4785)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4717)
    at java.util.regex.Pattern$BranchConn.match(Pattern.java:4568)
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3777)
    at java.util.regex.Pattern$Branch.match(Pattern.java:4604)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4658)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4785)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4717)
    at java.util.regex.Pattern$BranchConn.match(Pattern.java:4568)
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3777)
    at java.util.regex.Pattern$Branch.match(Pattern.java:4604)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4658)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4785)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4717)
    at java.util.regex.Pattern$BranchConn.match(Pattern.java:4568)
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3777)
    at java.util.regex.Pattern$Branch.match(Pattern.java:4604)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4658)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4785)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4717)
    at java.util.regex.Pattern$BranchConn.match(Pattern.java:4568)
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3777)
    at java.util.regex.Pattern$Branch.match(Pattern.java:4604)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4658)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4785)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4717)
    at java.util.regex.Pattern$BranchConn.match(Pattern.java:4568)
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3777)
    at java.util.regex.Pattern$Branch.match(Pattern.java:4604)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4658)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4785)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4717)
    at java.util.regex.Pattern$BranchConn.match(Pattern.java:4568)
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3777)
    at java.util.regex.Pattern$Branch.match(Pattern.java:4604)
    at java.util.regex.Pattern$GroupHead.match(Pattern.java:4658)
    at java.util.regex.Pattern$Loop.match(Pattern.java:4785)
    at java.util.regex.Pattern$GroupTail.match(Pattern.java:4717)
    at java.util.regex.Pattern$BranchConn.match(Pattern.java:4568)
    at java.util.regex.Pattern$CharProperty.match(Pattern.java:3777)
    at java.util.regex.Pattern$Branch.match(Pattern.java:4604)
java.lang.StackOverflowError

【问题讨论】:

  • 您是否尝试过使用 DOTALL for p6? (?s)(BENCH:)(.*)(BENCH)(.*)(CITATION) 这看起来很笨拙:(.|\\n)* 为什么要使用?
  • 可以通过使第一个量词变得惰性来提高性能 - 如果这不会影响您的结果:(?s)(BENCH:)(.*?)(BENCH)(.*)(CITATION)
  • 我已经尝试过您的建议,但它不适用于 java。
  • @AvinashRaj:另一个问题的答案没有给出解决方案,所以我重新打开了这个问题。

标签: java regex


【解决方案1】:

问题来自(.|\\n)*的一部分p6

Pattern p6=Pattern.compile("(BENCH:)((.|\\n)*)(BENCH)((.|\\n)*)(CITATION)");

(.|\\n)* 在 Oracle/OpenJDK JRE 上编译成以下结构,其实现使用递归(注意 GroupTail 回到 Loop)来匹配 non-deterministic 模式的重复(交替在实现中总是被认为是非确定性的)。

Prolog. Loop wrapper
Loop [732768bb]. Greedy quantifier {0,2147483647}
  GroupHead. (DEBUG) local=0
  Branch. Alternation (in printed order):
    Dot. (?:.), equivalent to [^\n\r\u0085\u2028\u2029]
    ---
    Single. Match code point: U+000A LINE FEED (LF)
    ---
  BranchConn [204d080d]. Connect branches to sequel.
  GroupTail [214b9e0c]. (DEBUG) local=0, group=2. --[next]--> Loop [732768bb]

在长字符串上,堆栈用完,所以你得到StackOverflowError

如果你想毫无例外地匹配任何字符,那么你应该单独使用.Pattern.DOTALL标志。

  • 您可以将标志传递给Pattern.compile(String regex, int flags) 方法以打开整个表达式的标志:

    Pattern p6 = Pattern.compile("(BENCH:)(.*)(BENCH)(.*)(CITATION)", Pattern.DOTALL);
    
  • 或者按照 Jonny 5 评论中的建议,您也可以使用内联标志 (?s)

    Pattern p6 = Pattern.compile("(?s)(BENCH:)(.*)(BENCH)(.*)(CITATION)");
    
  • 或者,您也可以打开子模式(?s:.*) 的标志:

    Pattern p6 = Pattern.compile("(BENCH:)(?s:(.*))(BENCH)(?s:(.*))(CITATION)");
    

对了,你确定要在p3 中匹配|onrable 吗?

Pattern p3 = Pattern.compile("(([H|h]on)|(HON)).*((ble)|BLE)(.*)");

如果你不想要它,从字符类中删除|

Pattern p3 = Pattern.compile("(([Hh]on)|(HON)).*((ble)|BLE)(.*)");

我还看到过多的捕获组。请检查并检查它们是否真的有必要。

【讨论】:

  • @AvinashRaj:也可以,但在这种情况下我不会推荐它。
【解决方案2】:

(.|\n)* 中的分支正在添加到堆栈中,并捕获每个字符。您要匹配的字符串足够长,以至于堆栈溢出。

一种选择是将其更改为.* 并使用选项DOTALL。另一种方法是仔细研究您要捕获的内容、原因、原因,然后使用不同的正则表达式达到相同的效果,或者构建您自己的简单状态机来扫描字符流。

看起来您要么在目录中递归地搜索(可能使用 grep),要么尝试解析某些内容(可能构建解析器,例如使用 javacc)。

使用StringBuilder 连接大量字符串。最好使用new String(Files.readAllBytes(path), charset) 来避免每一行作为自己的字符串的麻烦和垃圾收集。

删除您实际上不需要用于分支或捕获目的的任何分组。任何不需要捕获的分支组都应以?: 开头。您可能希望对其余部分使用命名组。首先在工具中测试您的正则表达式,甚至可以为您提供one that can write 一个 sn-p。

考虑| 在方括号字符类中的含义,以及类似地使括号类中只有一个字符的含义,例如.,

Pattern.compile 是一个静态方法,它只需要在每个模式中使用一次,而不是在每次递归中使用,也就是说,将这些行从方法中拉出并使用 [I've edit p6] 进入类:

private static Pattern p = Pattern.compile("Bench:(.*)");
private static Pattern p1 = Pattern.compile("Author:(.*)");
private static Pattern p2 = Pattern.compile("JUDGMENT(.*?)J\\.");
private static Pattern p3 = Pattern.compile("[Hh](on|ON).*(ble|BLE)(.*)");
private static Pattern p4 = Pattern.compile(",\\s*([^,]+),[^,]*\\b(J|JJ)\\.");
private static Pattern p5 = Pattern.compile("\\s\\w*(?=\\w*,\\sJ\\.*\\b)"); //? [.]* ?
private static Pattern p4 =
    Pattern.compile("\\w*(?=\\w*,*\\s*(JJ|L.J|C.J|J).\\s\\b)"); //? [,]* ?
private static Pattern p6 =
    Pattern.compile("BENCH:.*?BENCH.*?CITATION", Pattern.DOTALL);

如果您首先养成写作的习惯:"path\dir" + "\" + name"\t" + " ",然后将部分适当组合为 "path\dir\" + name"\t ",您会更清楚地看到类似 "path\dir"+"\"+name"\t"+" " 的内容.

最后,我会确定匹配器的范围并更改支撑格式,这可能就是我自己的问题:

package com.you.take.me.to.funky;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.nio.path.Files;
import java.nio.path.Path;
import java.nio.path.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class town {

  private static List<String> list = new ArrayList<>();
  private static List<String> misclist = new ArrayList<>();

  private static Pattern p0 = Pattern.compile("(Bench:)(.*)");
  private static Pattern p1 = Pattern.compile("(Author):(.*)");
  private static Pattern p2 = Pattern.compile("JUDGMENT(.*?)J[.]");
  private static Pattern p3 = Pattern.compile("(([H|h]on)|(HON)).*((ble)|BLE)(.*)");
  private static Pattern p4 = Pattern.compile(",\\s*([^,]+),[^,]*\\b(J|JJ)\\.");//CAKE
  private static Pattern p5 = Pattern.compile("\\s\\w*(?=\\w*[,]\\sJ[.]*\\b)");
  private static Pattern p4 =
      Pattern.compile("\\w*(?=\\w*[,]*\\s*((JJ)|(L.J)|(C.J)|(J))[.]\\s\\b)");
  private static Pattern p6 =
      Pattern.compile("BENCH:.*?BENCH.*?CITATION", Pattern.DOTALL);

  public static void main(String[] args) {
    Path path = Paths.get(args[0]);
    String str;
    try {
      str = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
    } catch (IOException e) {
      e.printStackTrace();
    }

    Matcher match = p0.matcher(str);
    if (match.find()) {
      Matcher match1 = p1.matcher(str);
      if (match1.find()) {
        // pathname  judgename  authorname
        list.add(path.toString() + 
                 "\t" + match.group(2) + 
                 "\t" + match1.group(2));
        System.out.println(match1.group(2));
      } else {
        list.add(path.toString() + "\t" + match.group(2) + "\t ");
        System.out.println(match.group(2));
      }
    } else {
      match = p1.matcher(str);
      if (match.find()) {
        list.add(path.toString() + "\t \t" + match.group(2));
      } else {
        match = p2.matcher(str);
        if (match.find()) {
          list.add(path.toString() + "\t" + match.group() + "\t ");
        } else {
          match = p3.matcher(str);
          if (match.find()) {
            list.add(path.toString() + "\t" + match.group() + "\t ");
          } else {
            match = p4.matcher(str);
            if (match.find()) {
              //do nothing
            } else {
              match = p5.matcher(str);
              if (match.find()) {
                list.add(path.toString() + "\t" + match.group() + "\t ");
                System.out.println(path.toString());
              } else {
                match = p6.matcher(str);
                if (match.find()) {
                  System.out.println("DEBUG MARKER");
                } else {
                  // list of documents which have no Judgenames
                  misclist.add(path.toString());
                  String name = UUID.randomUUID().toString();
                  try {
                    PrintWriter pw = new PrintWriter("/h/g/d/d/m/" + name);
                    pw.write(str);
                    pw.flush();
                  } catch (FileNotFoundException e) {
                    e.printStackTrace();
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-29
    • 1970-01-01
    相关资源
    最近更新 更多