Java 8 Streams:如何读取行内容指定的两行之间的行

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

当前问题陈述的输入是 -

INPUT.TXT

#START_OF_TEST_CASES

#DATA
key1:VA1
key2:VA2
key3:VA3
key4:VA4
key5:VA5
#DEND

#ENTRIES:
1{key1}{key1}{key3}
2{key2}{key2}{key1}
3{key3}{key1}{key2}
#EEND

现在我想读取这个文件并在#DATA和#DEND之间创建一行HashMap。 HashMap的键是':'的左侧部分,值是右侧部分。虽然我们可以迭代地实现这一点,但我想使用Java 8的Stream API来实现这一点。

java java-8 java-stream
3个回答
2
投票

不幸的是,Java 8流不支持两次匹配之间的元素提取。在Java 9中,您可以使用

Map<String,String> map;
try(Stream<String> stream = Files.lines(path)) {
    map = stream
        .dropWhile(s -> !s.equals("#DATA")).skip(1)
        .takeWhile(s -> !s.equals("#DEND"))
        .filter(Pattern.compile("^[^#].*:").asPredicate())
        .map(item -> item.split(":", 2))
        .collect(Collectors.toMap(parts->parts[0], parts->parts[1]));
}
// use the map
map.forEach((k,v)->System.out.println(k+" -> "+v));

dropWhile将在第一个匹配元素之前删除所有元素,skip(1)将跳过匹配元素,takeWhile在第一个元素匹配结束条件后有效地删除所有元素。

使用filter模式的下一个^[^#].*:步骤将跳过以#开头或不包含:的所有行。剩下的步骤很简单。当指定2split的限制时,它不会在遇到第一个:后搜索后续的:s。

在Java 8下,可以在流操作之前使用Scanner实现在两个匹配之间提取部分:

String part;
try(Scanner s = new Scanner(path)) {
    part = s.findWithinHorizon("(?<=\\R#DATA\\R)(.|\\R)*(?=\\R#DEND\\R)", 0);
}
Map<String,String> map = Pattern.compile("\\R").splitAsStream(part)
    .filter(Pattern.compile("^[^#].*:").asPredicate())
    .map(item -> item.split(":", 2))
    .collect(Collectors.toMap(parts->parts[0], parts->parts[1]));
// use the map
map.forEach((k,v)->System.out.println(k+" -> "+v));

0
投票

如果您看到#DATA和#DEND之间的谎言包含':',那么我想出了以下解决方案 -

    File file = new File("Input.txt");
    try {
        Map<String,String> map = Files.lines(file.toPath())
                                     .filter(list -> list.contains(":"))
                                     .map(item -> item.split(":"))
                                     .filter(arr -> arr.length > 1)
                                     .collect(Collectors.toMap(parts->parts[0], parts->parts[1]));
        System.out.println(map.values());
    } catch (IOException e) {
        e.printStackTrace();
    }

上面的代码首先只过滤包含冒号':'的行,然后根据冒号拆分这些行,之后,我们只过滤长度大于1的列表,因为如果你仔细看到input.txt文件,你可以找到“#ENTRIES:”包含冒号,但在此之后不包含任何字符。获得所需数据后,我们创建HashMap。


-1
投票

以下代码模式可以解决您的问题:

    List<String> lines = Files.readAllLines(Paths.get("Input.txt"));
    int from = lines.indexOf("#DATA") + 1;
    int to  = lines.indexOf("#DEND");
    Map<String, String> map = lines.stream()
            .skip(from)
            .limit(to - from)
            .map(s -> s.split(":"))
            .collect(Collectors.toMap(pair -> pair[0], pair -> pair[1]));
© www.soinside.com 2019 - 2024. All rights reserved.