【问题标题】:Match a pattern and write the stream to a file using Java 8 Stream匹配模式并使用 Java 8 Stream 将流写入文件
【发布时间】:2016-05-25 16:01:37
【问题描述】:

我正在尝试读取一个巨大的文件并提取“引号”中的文本并将这些行放入一个集合中,然后使用 Java 8 Stream 将该集合的内容写入一个文件。

public class DataMiner {

    private static final Pattern quoteRegex = Pattern.compile("\"([^\"]*)\"");

    public static void main(String[] args) {

        String fileName = "c://exec.log";
        try (Stream<String> stream = Files.lines(Paths.get(fileName))) {
            Set<String> dataSet = stream.
                    //How do I Perform pattern match here
                    .collect(Collectors.toSet());
            Files.write(Paths.get(fileName), dataSet);

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

请帮助我。谢谢!

编辑:问题的答案..

  1. 不,没有多个引用文本。
  2. 我可以使用简单的循环。但我想使用 Java 8 流

【问题讨论】:

  • 使用.map(...)
  • 1) 引用的文本可以跨越多行吗? 2)如果一行有abc "def" ghi "jkl" mno,应该收集什么?
  • 文档总是一个很好的起点。例如。 Stream#map(Function)
  • @khelwood 我不确定这是否适用于他的要求。假设他使用.map(...),他将能够编写拆分字符串,但返回的字符串将是数组或其他结构中的组。但是他正在处理的流期待一个字符串。你有他如何做到这一点的例子吗?
  • 有什么理由要使用 Java 8 流而不是简单循环?另外,创建将存储所有结果的临时 Set 的意义何在。您可以将每个找到的结果直接写入文件中(假设它与您正在读取的文件不同)。

标签: java


【解决方案1】:

不幸的是,Java 正则表达式类不提供匹配结果的流,只提供splitAsStream() 方法,但您不想拆分。

注意:added in Java 9 一直是 Matcher.results()

但是,您可以自己为其创建一个通用帮助类:

public final class PatternStreamer {
    private final Pattern pattern;
    public PatternStreamer(String regex) {
        this.pattern = Pattern.compile(regex);
    }
    public Stream<MatchResult> results(CharSequence input) {
        List<MatchResult> list = new ArrayList<>();
        for (Matcher m = this.pattern.matcher(input); m.find(); )
            list.add(m.toMatchResult());
        return list.stream();
    }
}

然后使用flatMap(),您的代码变得简单:

private static final PatternStreamer quoteRegex = new PatternStreamer("\"([^\"]*)\"");
public static void main(String[] args) throws Exception {
    String inFileName = "c:\\exec.log";
    String outFileName = "c:\\exec_quoted.txt";
    try (Stream<String> stream = Files.lines(Paths.get(inFileName))) {
        Set<String> dataSet = stream.flatMap(quoteRegex::results)
                                    .map(r -> r.group(1))
                                    .collect(Collectors.toSet());
        Files.write(Paths.get(outFileName), dataSet);
    }
}

由于您一次只处理一行,所以临时的List 就可以了。如果输入字符串很长并且会有很多匹配项,那么Spliterator 将是更好的选择。见How do I create a Stream of regex matches?

【讨论】:

  • 完美!正是我想知道/学习的。非常感谢@Andreas
  • 这是在 Java 9 中添加的,非常酷。我在查看更改时一定忽略了它。
  • 如果您通过临时数据结构而不是即时创建流,例如在this answer 中,建议使用Stream.Builder(另见Stream.builder())而不是@987654337 @,因为这个构建器特别针对这个用例进行了优化。
猜你喜欢
  • 2017-10-04
  • 2021-03-14
  • 2012-06-28
  • 1970-01-01
  • 2021-10-30
  • 2020-07-08
  • 1970-01-01
  • 2012-04-08
  • 1970-01-01
相关资源
最近更新 更多