You can simply concatenate the streams:
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);
}
but note that this will perform three individual searches through each line, which might not only imply lower performance, but also that the order of the matches within one line will not reflect their actual occurrence. It doesn’t seem to be an issue with your patterns, but individual searches even imply possible overlapping matches.
The PatternStreamer
of that linked answer also greedily collects the matches of one string into an ArrayList
before creating a stream. A Spliterator
based solution like in this answer is preferable.
Since numerical group references preclude just combining the patterns in a (pattern1|pattern2|pattern3)
manner, a true streaming over matches of multiple different patterns will be a bit more elaborated:
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;
}
}
This facility allows to match multiple pattern in a (pattern1|pattern2|pattern3)
fashion while still having the original groups of each pattern. So when searching for hell
and llo
in hello
, it will find hell
and not llo
. A difference is that there is no guaranteed order if more than one pattern matches at the same position.
This can be used like
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);
}
While the overloaded method would allow to use MultiPatternSpliterator.matches(s, reTimeStamp, reHostName, reServiceTime)
using the pattern strings to create a stream, this should be avoided within a flatMap
operation that would recompile every regex for every input line. That’s why the code above compiles all patterns into an array first. This is what your original code also does by instantiating the PatternStreamer
s outside the stream operation.