累积 Java Stream 然后再处理它

问题描述 投票:0回答:1

我有一份如下所示的文档:

数据.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());

这将返回已处理的 MyClass 列表。可以并行运行,一切正常。

问题是我现在有这个:

数据2.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 java-8 java-stream reduce collectors
1个回答
2
投票

这是

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());
}
© www.soinside.com 2019 - 2024. All rights reserved.