累积一个 Java 流然后才对其进行处理
Accumulate a Java Stream and only then process it
我有一个如下所示的文档:
data.txt
100, "some text"
101, "more text"
102, "even more text"
我使用正则表达式处理它并返回一个新的处理文件如下:
Stream<String> lines = Files.lines(Paths.get(data.txt);
Pattern regex = Pattern.compile("([\d{1,3}]),(.*)");
List<MyClass> result =
lines.map(regex::matcher)
.filter(Matcher::find)
.map(m -> new MyClass(m.group(1), m.group(2)) //MyClass(int id, String text)
.collect(Collectors.toList());
此 returns 处理的 MyClass 列表。可以运行并联,一切正常
问题是我现在有这个:
data2.txt
101, "some text
the text continues in the next line
and maybe in the next"
102, "for a random
number
of lines"
103, "until the new pattern of new id comma appears"
所以,我需要以某种方式加入从流中读取的行,直到出现新的匹配项。 (类似缓冲区的东西?)
我尝试收集字符串然后收集 MyClass(),但没有成功,因为我实际上无法拆分流。
想到 Reduce 来连接行,但我只会连接行,我无法减少并生成新的行流。
关于如何使用 java 8 个流解决此问题的任何想法?
这是 java.util.Scanner
的工作。对于即将到来的 Java 9,您可以这样写:
List<MyClass> result;
try(Scanner s=new Scanner(Paths.get("data.txt"))) {
result = s.findAll("(\d{1,3}),\s*\"([^\"]*)\"")
//MyClass(int id, String text)
.map(m -> new MyClass(Integer.parseInt(m.group(1)), m.group(2)))
.collect(Collectors.toList());
}
result.forEach(System.out::println);
但是由于 Stream
生成 findAll
在 Java 8 下不存在,我们需要一个辅助方法:
private static Stream<MatchResult> matches(Scanner s, String pattern) {
Pattern compiled=Pattern.compile(pattern);
return StreamSupport.stream(
new Spliterators.AbstractSpliterator<MatchResult>(1000,
Spliterator.ORDERED|Spliterator.NONNULL) {
@Override
public boolean tryAdvance(Consumer<? super MatchResult> action) {
if(s.findWithinHorizon(compiled, 0)==null) return false;
action.accept(s.match());
return true;
}
}, false);
}
用这个辅助方法替换findAll
,我们得到
List<MyClass> result;
try(Scanner s=new Scanner(Paths.get("data.txt"))) {
result = matches(s, "(\d{1,3}),\s*\"([^\"]*)\"")
// MyClass(int id, String text)
.map(m -> new MyClass(Integer.parseInt(m.group(1)), m.group(2)))
.collect(Collectors.toList());
}
我有一个如下所示的文档:
data.txt
100, "some text"
101, "more text"
102, "even more text"
我使用正则表达式处理它并返回一个新的处理文件如下:
Stream<String> lines = Files.lines(Paths.get(data.txt);
Pattern regex = Pattern.compile("([\d{1,3}]),(.*)");
List<MyClass> result =
lines.map(regex::matcher)
.filter(Matcher::find)
.map(m -> new MyClass(m.group(1), m.group(2)) //MyClass(int id, String text)
.collect(Collectors.toList());
此 returns 处理的 MyClass 列表。可以运行并联,一切正常
问题是我现在有这个:
data2.txt
101, "some text
the text continues in the next line
and maybe in the next"
102, "for a random
number
of lines"
103, "until the new pattern of new id comma appears"
所以,我需要以某种方式加入从流中读取的行,直到出现新的匹配项。 (类似缓冲区的东西?)
我尝试收集字符串然后收集 MyClass(),但没有成功,因为我实际上无法拆分流。
想到 Reduce 来连接行,但我只会连接行,我无法减少并生成新的行流。
关于如何使用 java 8 个流解决此问题的任何想法?
这是 java.util.Scanner
的工作。对于即将到来的 Java 9,您可以这样写:
List<MyClass> result;
try(Scanner s=new Scanner(Paths.get("data.txt"))) {
result = s.findAll("(\d{1,3}),\s*\"([^\"]*)\"")
//MyClass(int id, String text)
.map(m -> new MyClass(Integer.parseInt(m.group(1)), m.group(2)))
.collect(Collectors.toList());
}
result.forEach(System.out::println);
但是由于 Stream
生成 findAll
在 Java 8 下不存在,我们需要一个辅助方法:
private static Stream<MatchResult> matches(Scanner s, String pattern) {
Pattern compiled=Pattern.compile(pattern);
return StreamSupport.stream(
new Spliterators.AbstractSpliterator<MatchResult>(1000,
Spliterator.ORDERED|Spliterator.NONNULL) {
@Override
public boolean tryAdvance(Consumer<? super MatchResult> action) {
if(s.findWithinHorizon(compiled, 0)==null) return false;
action.accept(s.match());
return true;
}
}, false);
}
用这个辅助方法替换findAll
,我们得到
List<MyClass> result;
try(Scanner s=new Scanner(Paths.get("data.txt"))) {
result = matches(s, "(\d{1,3}),\s*\"([^\"]*)\"")
// MyClass(int id, String text)
.map(m -> new MyClass(Integer.parseInt(m.group(1)), m.group(2)))
.collect(Collectors.toList());
}