【问题标题】:Performing regex on a stream在流上执行正则表达式
【发布时间】:2010-06-10 10:49:47
【问题描述】:

我有一些大型文本文件,我将对其进行连续匹配(只是捕获,而不是替换)。我认为将整个文件保存在内存中并不是一个好主意,而是使用Reader

我对输入的了解是,如果有匹配项,它不会跨越超过 5 行。所以我的想法是有一些缓冲区来保存这 5 行左右,做第一次搜索,然后继续。但它必须“知道”正则表达式匹配在哪里结束才能正常工作。例如,如果匹配在第 2 行结束,它应该从这里开始下一次搜索。有没有可能以一种高效的方式来做这样的事情?

【问题讨论】:

    标签: java regex


    【解决方案1】:

    您可以使用ScannerfindWithinHorizon 方法:

    Scanner s = new Scanner(new File("thefile"));
    String nextMatch = s.findWithinHorizon(yourPattern, 0);
    

    来自findWithinHorizon上的api:

    如果horizo​​n 为0,则horizo​​n 被忽略,并且此方法继续搜索输入以寻找指定的模式而不受限制。在这种情况下,它可能会缓冲所有搜索模式的输入。

    附注:在多行匹配时,您可能需要查看常量Pattern.MULTILINEPattern.DOTALL

    【讨论】:

    • +1;并阅读 API 以了解 Scanner 如何处理 IOException
    【解决方案2】:

    Streamflyer 能够对字符流应用正则表达式。

    请注意,我是它的作者。

    【讨论】:

    • 太糟糕了,您的库不再维护。 :-( 有什么好的选择吗?
    【解决方案3】:

    正则表达式引擎的 java 实现看起来不适合流式处理。

    我宁愿提倡另一种基于“导数组合器”的方法。

    研究员 Matt Might 在他的博客上发表了有关“导数组合器”的相关文章,并在此处建议了 Scala 实现:

    就我而言,我通过添加一些“捕获”功能成功地改进了这个实现,但我觉得它可能会对内存消耗产生重大影响。

    【讨论】:

      【解决方案4】:
      import java.io.*;  //BufferedReader //FileReader //FileWriter //PrintWriter
      import java.io.IOException;
      import java.util.Scanner;
      import java.util.regex.*;
      
      public class ScannerReader { 
      
          public static void main(String[] args) {
      
              try {  
                  ReadDataFromFileTestRegex("[A-Za-z_0-9-%$!]+@[A-Za-z_0-9-%!$]+\\.[A-Za-z]{2,4}",
                                            "C:\\Users\\Admin\\Desktop\\TextFiles\\Emails.txt",
                                            "C:\\Users\\Admin\\Desktop\\TextFiles\\\\output.txt");
              } catch (Exception e) {
                  System.out.println("File is not found");
                  e.printStackTrace();
              }       
          }
      
          public static void ReadDataFromFileTestRegex (String theReg, String FileToRead, String FileToWrite) throws Exception {
      
              PrintWriter Pout = new PrintWriter(FileToWrite);            
              Pattern p = Pattern.compile(theReg); 
              BufferedReader br = new BufferedReader (new FileReader(FileToRead)); 
              String line = br.readLine();       
              while (line != null) {          
                  Matcher m = p.matcher(line);
                  while (m.find()) {
                      if (m.group().length() != 0) {
                          System.out.println( m.group().trim());
                      }             
                      System.out.println("Start index: " + m.start());
                      System.out.println("End index  : " + m.end());
                      Pout.println(m.group());  //print the result to the output file
                  }
                  line = br.readLine();
              }
              Pout.flush();   
              br.close();
              Pout.close();
          }
      }
      

      【讨论】:

      • 您能否通过添加示例代码用法和示例输出来增强您有前途的帖子?
      【解决方案5】:

      也许Scanner.matchAll() 就是您要找的。它简化了我的代码。

      try(var scanner = new Scanner(Path.of(path), StandardCharsets.UTF_8)){
          var result = scanner.findAll(PATTERN)
                      .map(MatchResult::group)
                      .collect(Collectors.toSet());
      }
      
      

      【讨论】:

        【解决方案6】:

        使用 Java8,您可以非常简单地并可能并行执行此操作-

        // Create a pattern-matcher
        private static final Pattern emailRegex = Pattern.compile("([^,]+?)@([^,]+)");
        
        //Read content of a file
        String fileContent = Files.lines(Path.get("/home/testFile.txt")
                                      .collect(Collector.join(" "));
        // Apply the pattern-matcher
        List<String> results = matcherStream(emailRegex.matcher(fileContent))
                                   .map(b -> b[2])
                                   .collect(Collector.toList()));
        

        另一种方式可以是-

        List<String> results = Files.lines(Path.get("/home/testFile.txt")
                                      .parallelStream()
                                      .forEach(s -> "use regex")
                                      .collect(Collector.toList());
        

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-01-21
        • 2022-06-15
        • 1970-01-01
        • 2016-06-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-07
        • 1970-01-01
        相关资源
        最近更新 更多