当前位置: 首页 > 知识库问答 >
问题:

拆分器跳过部分文本

祁承望
2023-03-14

我遇到了Streams的DropWhileTakeWhile方法的问题,因为spliterator跳过特定模式(奇数或偶数)的文本部分。应该做什么来处理文本的所有部分?我在这里的方法:

void read(Path filePath) {
    try {
        Stream<String> lines = Files.lines(filePath);
        while (true) {
            Spliterator<String> spliterator = lines.dropWhile(line -> !line.startsWith("FAYSAL:")).spliterator();
            Stream<String> portion = fetchNextPortion(spliterator);
            if(spliterator.estimateSize() == 0)
                break;
            portion .forEach(System.out::println);
            lines = StreamSupport.stream(spliterator, false);
        }
        lines.close();
    }
    catch (IOException e) {
        e.printStackTrace();
    }
}

private Stream<String> fetchNextPortion(Spliterator<String> spliterator) {
    return StreamSupport.stream(spliterator, false)
            .filter(this::isValidReportName)
            .peek(System.out::println)
            .findFirst()
            .map( first -> Stream.concat(Stream.of(first),
                    StreamSupport.stream(spliterator, false).takeWhile(line -> !line.startsWith("FAYSAL:")))).orElse(Stream.empty());
}

示例输入为:

FAYSAL: 1
Some text here
Some text here
FAYSAL: 2
Some text here
Some text here
FAYSAL: 3
Some text here
Some text here
FAYSAL: 4
Some text here
Some text here

它将跳过Faysal:2和Faysal:4

共有1个答案

戚高洁
2023-03-14

应该做什么来处理文本的所有部分?

你可以选择一个不同的方法。

您的代码在我的计算机上产生了一个StackOverflowError(还有一个对FetchNextChunk的调用,但是一个名为FetchNextPartition的方法,所以我也不确定这一点),所以我没有尝试调试它,而是想出了一种不同的方法来拆分输入。鉴于我的方法在内存中包含整个字符串,它可能不适合较大的文件。我以后可能会用Streams开发出一个版本。

基本假设:您希望将输入文本分成几个部分,每个部分都以一个以“faysal:”开头的字符串开始。

这个想法与您的方法类似,但不是基于spliterator,也没有使用dropWhile。相反,它会找到以“faysal:”开头的第一个字符串(我假定这就是isValidReportName所做的;方法的代码不在问题中),并将所有内容处理到下一部分开始。将找到的第一个元素添加为列表的第一个元素,然后将集合添加到以后可以使用的列表中。然后从原始列表中删除收集的行数。

完整代码:

import java.util.*;
import java.util.stream.Collectors;

class Main {

    public static void main(String[] args) {
        Main m = new Main();
        System.out.println(m.partitionTextByStringStart(m.getString()));
    }

    private List<List<String>> partitionTextByStringStart(String text) {
        List<List<String>> partitions = new ArrayList<>();
        List<String> lines = Arrays.asList(text.split("\n"));

        while (!lines.isEmpty()) {
            String first = lines.stream().filter(this::isValidReportName).findFirst().orElse("This is prolly bad");
            List<String> part = lines.stream().skip(1).takeWhile(l -> !l.startsWith("FAYSAL:")).collect(Collectors.toList());
            part.add(0, first);

            partitions.add(part);
            lines = lines.subList(part.size(), lines.size());
        }

        return partitions;
    }

    private boolean isValidReportName(String x) {
        return x.startsWith("FAYSAL:");
    }

    private String getString() {
        return "FAYSAL: 1\n" +
                "Some text here1\n" +
                "Some text here1\n" +
                "FAYSAL: 2\n" +
                "Some text here2\n" +
                "Some text here2\n" +
                "FAYSAL: 3\n" +
                "Some text here3\n" +
                "Some text here3\n" +
                "FAYSAL: 4\n" +
                "Some text here4\n" +
                "Some text here4";
    }

}

(注意:我在这里使用了一个静态字符串,而不是文件读取来制作完整的代码示例;您可以相应地改编您的代码)

编辑:经过一些研究,我发现使用StreamEx(Github)(Maven)库将这些东西分组在流中是非常容易的。在这个答案中,我找到了一个关于streamex#groupruns函数的注释,该函数正是这样做的:

private Stream<Stream<String>> partitionStreamByStringStart(Stream<String> lineStream) {
    return StreamEx.of(lineStream).groupRuns((l1, l2) -> !l2.startsWith("FAYSAL:")).map(Collection::stream);
}

若要查看其工作情况,您可以添加

System.out.println(m.partitionStreamByStringStart(m.getStream()).map(
    s -> s.collect(Collectors.toList())
).collect(Collectors.toList()));

到主函数和

private Stream<String> getStream() {
    return Stream.of(getString().split("\n"));
}

在上面的完整代码示例的主类中的某个地方。

 类似资料:
  • 我只有一个具有大xml文件最后顺序的文件,而不是许多小xml文件。你能告诉我出了什么问题吗?太感谢你们了!

  • 问题内容: 我有这样的输入文件: 所需的任务是按由特殊行分隔的部分读取文件,在这种情况下,该行为空行,例如[out]: 通过这样做,我一直在获得所需的输出: 但是,如果特殊行是以例如以下开头的行: 我必须这样做: 如果我允许拥有分隔符参数,则可以尝试以下操作: 但是有没有办法我不对所有可能的分隔符进行硬编码? 问题答案: 传递谓词怎么样? 用法:

  • 作为映射器输出而生成的部件文件是否只作为part-m-00000、Part-m-00001等工作,从而表示第一个输入拆分、第二个输入拆分等等,它们是否按顺序生成??

  • 拆分项目文件 到目前为止我们自定义了一个build.gradle和settings.gradle文件,随着你添加越来越多的子项目和任务到build.gradle中,代码的维护性将会下降。通过给每个子项目建立一个单独的build.gradle文件可以解决这个问题。 接下来我们在每个子项目的目录下创建一个build.gradle文件,目录如下: 现在你可以把构建逻辑从原先的build脚本中拆分开来放到

  • 我在思考这个问题的答案:如何在任何Java映射实现上测试空键? 我的第一个想法是检查映射的键集的是否具有特征: JavaDoc说: 表示源保证遇到的元素不为空的特征值。(例如,这适用于大多数并发集合、队列和映射。) 在回答之前,我做了一些检查: 即使自然排序不允许空键,没有提供的的也没有此特性。 更令人惊讶的是,键集的s和本身不具有此特性。 我知道< code>spliterator()的结果。h