这就是Java 9解决方案最有可能的样子:
Matcher m = Pattern.compile("name: '(.+)'").matcher("");
try(Stream<String> lines = Files.lines(ruleFile)) {
lines.flatMap(line -> m.reset(line).results().limit(1))
.forEach(mr -> System.out.println(mr.group(1)));
}
它使用方法 Matcher.results()
返回所有匹配项的流。将行流与匹配流通过组合在一起,使我们能够处理文件的所有匹配项。由于您的原始代码只处理一行的第一个匹配项,因此我只需将 a 添加到每行的匹配项中即可获得相同的行为。flatMap
limit(1)
不幸的是,Java 8中缺少此功能,但是,潜入即将发布的版本有助于了解临时解决方案的外观:
Matcher m = Pattern.compile("name: '(.+)'").matcher("");
try(Stream<String> lines = Files.lines(ruleFile)) {
lines.flatMap(line -> m.reset(line).find()? Stream.of(m.toMatchResult()): null)
.forEach(mr -> System.out.println(mr.group(1)));
}
为了简化子流的创建,此解决方案利用仅打算进行第一个匹配,并首先创建单个元素流。
但请注意,对于问题的模式,我们是否限制匹配的数量并不重要,因为会贪婪地匹配所有字符,直到该行的最后一个后续,因此另一个匹配是不可能的。当使用不情愿的量词时,情况就不同了,例如使用量词,直到下一个量词而不是最后一个量词,或者禁止显式跳过,就像.'name: '(.+)'
.+
'
name: '(.*?)'
'
'
name: '([^']*)'
上面的解决方案使用共享,它适用于单线程用法(这不太可能从并行处理中受益)。但是,如果你想在线程安全方面,你可以只共享一个并创建一个而不是调用:Matcher
Pattern
Matcher
m.reset(line)
Pattern pattern = Pattern.compile("name: '(.*)'");
try(Stream<String> lines = Files.lines(ruleFile)) {
lines.flatMap(line -> pattern.matcher(line).results().limit(1))
.forEach(mr -> System.out.println(mr.group(1)));
}
与 Java 8 一起使用
try(Stream<String> lines = Files.lines(ruleFile)) {
lines.flatMap(line -> {Matcher m=pattern.matcher(line);
return m.find()? Stream.of(m.toMatchResult()): null;})
.forEach(mr -> System.out.println(mr.group(1)));
}
由于引入了局部变量,这并不是那么简洁。这可以通过前面的操作来避免,但是当我们在这一点上时,只要我们每行只进行一场比赛,我们就不需要那么:map
flatMap
try(Stream<String> lines = Files.lines(ruleFile)) {
lines.map(pattern::matcher).filter(Matcher::find)
.forEach(m -> System.out.println(m.group(1)));
}
由于每个都以非干扰方式仅使用一次,因此其可变性在这里不会受到伤害,并且不需要转换为不可变性。Matcher
MatchResult
但是,如果有必要,这些解决方案无法扩展到每行处理多个匹配项...