Выполнение регулярного выражения в потоке
У меня есть несколько больших текстовых файлов, которые они собираются закрепить последовательным сопоставлением (просто захватывая, а не заменяя). Я думаю, что не такая хорошая идея сохранить весь файл в памяти, а скорее использовать 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());