Unfortunately, Java 8 streams do not support such extraction of elements in-between two matches. In Java 9, you could use
Map<String,String> map;
try(Stream<String> stream = Files.lines(path)) {
map = stream
.dropWhile(s -> !s.equals("#DATA")).skip(1)
.takeWhile(s -> !s.equals("#DEND"))
.filter(Pattern.compile("^[^#].*:").asPredicate())
.map(item -> item.split(":", 2))
.collect(Collectors.toMap(parts->parts[0], parts->parts[1]));
}
// use the map
map.forEach((k,v)->System.out.println(k+" -> "+v));
dropWhile
will drop all elements before the first matching element, skip(1)
will skip the matching element, takeWhile
effectively removes all elements after the first element matching the end criteria.
The next filter
step using the pattern ^[^#].*:
will skip all lines starting with #
or not containing a :
. The remaining steps are straight-forward. When specifying a limit of 2
to split
, it will not search for subsequent :
s after encountering the first :
.
Under Java 8, extracting the part between the two matches can be implemented with a Scanner
before the stream operation:
String part;
try(Scanner s = new Scanner(path)) {
part = s.findWithinHorizon("(?<=\\R#DATA\\R)(.|\\R)*(?=\\R#DEND\\R)", 0);
}
Map<String,String> map = Pattern.compile("\\R").splitAsStream(part)
.filter(Pattern.compile("^[^#].*:").asPredicate())
.map(item -> item.split(":", 2))
.collect(Collectors.toMap(parts->parts[0], parts->parts[1]));
// use the map
map.forEach((k,v)->System.out.println(k+" -> "+v));