在流上执行正则表达式

时间:2010-06-10 10:49:47

标签: java regex

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

我对输入的了解是,如果匹配,则不会超过5行。所以我的想法是有一些缓冲区只保留这5行,或者左右,进行第一次搜索,然后继续。但它必须“知道”正则表达式匹配结束的地方才能发挥作用。例如,如果匹配在第2行结束,它应该从这里开始下一次搜索。是否有可能以高效的方式做这样的事情?

6 个答案:

答案 0 :(得分:26)

您可以使用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 :(得分:2)

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

请注意,我是它的作者。

答案 2 :(得分:2)

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

我宁愿提倡另一种以衍生组合者为基础的方法"。

研究员Matt Might发表了关于"衍生组合者的相关文章"在他的博客上,建议在这里实施Scala:

在我这边,我通过添加一些" capture"成功地改进了这个实现。能力,但我觉得它可能会对记忆消耗产生重大影响。

答案 3 :(得分:0)

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();
    }
}

答案 4 :(得分:0)

也许您正在寻找Scanner.matchAll()。它简化了我的代码。

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

答案 5 :(得分:-5)

使用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());