Выполнение регулярного выражения в потоке

У меня есть несколько больших текстовых файлов, которые они собираются закрепить последовательным сопоставлением (просто захватывая, а не заменяя). Я думаю, что не такая хорошая идея сохранить весь файл в памяти, а скорее использовать Reader.

Что я знаю о вводе, так это то, что если есть совпадение, оно не будет охватывать более 5 строк. Поэтому моя идея состояла в том, чтобы иметь какой-то буфер, который просто держит эти 5 строк или около того, выполняет первый поиск и продолжает. Но он должен "знать", где матч регулярных выражений заканчивался для этого. например, если совпадение заканчивается в строке 2, он должен начать следующий поиск отсюда. Возможно ли сделать что-то подобное в эффективном способе?

Ответы

Ответ 1

Вы можете использовать метод Scanner и findWithinHorizon:

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

Из api на findWithinHorizon:

Если горизонт равен 0, горизонт игнорируется, и этот метод продолжает поиск через вход, который ищет указанный шаблон без привязки. В этом случае он может буферизовать весь входной поиск шаблона.

Примечание: при сопоставлении на нескольких строках вы можете посмотреть константы Pattern.MULTILINE и Pattern.DOTALL.

Ответ 2

Streamflyer может применять регулярные выражения в символьных потоках.

Обратите внимание, что я автор его.

Ответ 3

Java-реализация механизма регулярных выражений выглядит непригодной для потоковой обработки.

Я предпочел бы пропагандировать другой подход, основанный на "производных комбинаторах".

Исследователь Мэтт Майт опубликовал в своем блоге соответствующие сообщения о "производных комбинаторах" и предлагает реализацию 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-%$!][email protected][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

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