一个扩展,您可以简单地串联流:
String inFileName = "Sample.log";
String outFileName = "Sample_output.log";
try (Stream<String> stream = Files.lines(Paths.get(inFileName))) {
List<String> timeStamp = stream
.flatMap(s -> Stream.concat(quoteRegex1.results(s),
Stream.concat(quoteRegex2.results(s), quoteRegex3.results(s))))
.map(r -> r.group(1))
.collect(Collectors.toList());
timeStamp.forEach(System.out::println);
//Files.write(Paths.get(outFileName), dataSet);
}
但请注意,这将通过各行执行三个独立的搜索,这可能不仅意味着性能较低,而且一行内的匹配顺序不会反映其实际发生的情况。它似乎不是你的模式的问题,但个人搜索甚至意味着可能的重叠匹配。
该链接答案的PatternStreamer
也会在创建流之前贪婪地将一个字符串的匹配项收集到ArrayList
中。像this answer这样基于Spliterator
的解决方案是优选的。
由于数值组的引用排除只是在一个(pattern1|pattern2|pattern3)
方式组合的图案,在多个不同的图案匹配一个真正的流将是更进一步的描述:
public final class MultiPatternSpliterator
extends Spliterators.AbstractSpliterator<MatchResult> {
public static Stream<MatchResult> matches(String input, String... patterns) {
return matches(input, Arrays.stream(patterns)
.map(Pattern::compile).toArray(Pattern[]::new));
}
public static Stream<MatchResult> matches(String input, Pattern... patterns) {
return StreamSupport.stream(new MultiPatternSpliterator(patterns,input), false);
}
private Pattern[] pattern;
private String input;
private int pos;
private PriorityQueue<Matcher> pendingMatches;
MultiPatternSpliterator(Pattern[] p, String inputString) {
super(inputString.length(), ORDERED|NONNULL);
pattern = p;
input = inputString;
}
@Override
public boolean tryAdvance(Consumer<? super MatchResult> action) {
if(pendingMatches == null) {
pendingMatches = new PriorityQueue<>(
pattern.length, Comparator.comparingInt(MatchResult::start));
for(Pattern p: pattern) {
Matcher m = p.matcher(input);
if(m.find()) pendingMatches.add(m);
}
}
MatchResult mr = null;
do {
Matcher m = pendingMatches.poll();
if(m == null) return false;
if(m.start() >= pos) {
mr = m.toMatchResult();
pos = mr.end();
}
if(m.region(pos, m.regionEnd()).find()) pendingMatches.add(m);
} while(mr == null);
action.accept(mr);
return true;
}
}
该工具允许以匹配在多模式(pattern1|pattern2|pattern3)
时尚,同时仍然有每个模式的原始组。因此,当在hello
中搜索hell
和时,它会找到hell
而不是。不同之处在于,如果多个模式在相同位置匹配,则没有保证顺序。
这可以用来像
Pattern[] p = Stream.of(reTimeStamp, reHostName, reServiceTime)
.map(Pattern::compile)
.toArray(Pattern[]::new);
try (Stream<String> stream = Files.lines(Paths.get(inFileName))) {
List<String> timeStamp = stream
.flatMap(s -> MultiPatternSpliterator.matches(s, p))
.map(r -> r.group(1))
.collect(Collectors.toList());
timeStamp.forEach(System.out::println);
//Files.write(Paths.get(outFileName), dataSet);
}
虽然重载方法将允许使用MultiPatternSpliterator.matches(s, reTimeStamp, reHostName, reServiceTime)
使用图案字符串来创建流,这应该一个flatMap
操作中被避免,将重新编译每正则表达式对每个输入线。这就是为什么上面的代码首先将所有模式编译成数组的原因。这是您的原始代码通过在流操作之外实例化PatternStreamer
所做的工作。
哦,这是精心制作的... – Eugene
很好的解释。 –
如果我仅匹配2个模式(例如,Stream.of(reTimeStamp,reHostName)),那么在仅读取大文件(5GB)时也会注意到一个奇怪的行为,该流能够在10分钟内完美地读取整个文件并打印输出。当我添加像Stream.of(reTimeStamp,reHostName,reServiceTime)这样的第三个模式并且在同一个文件java进程上再次运行的那一刻,通过将文件永久保存在内存中(通过VisualVM监视)并且不会因任何错误而崩溃。这与Stream.concat(regex1,regex2)的工作方式相同。 Stream.concat(regex1,regex2,regex3) - Java进程挂起。 – Shan