【问题标题】:How to find total count of Words, total count of Vowels, total count of Special Character in a text file using java 8如何使用java 8查找文本文件中的单词总数,元音总数,特殊字符总数
【发布时间】:2019-03-26 03:30:19
【问题描述】:

我有一个文本文件,我想检查一下
- 文件中的总字数
- 文件中的总元音计数
- 文件中的总特殊字符

通过使用 Java 8 流。

如果可能,我希望在单次迭代中输出为地图,即

{"totalWordCount":10,"totalVowelCount":10,"totalSpecialCharacter":10}

我试过下面的代码

    Long wordCount=Files.lines(child).parallel().flatMap(line -> Arrays.stream(line.trim().split(" ")))
                            .map(word -> word.replaceAll("[^a-zA-Z]", "").toLowerCase().trim())
                            .filter(word -> !word.isEmpty())
                            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())).values().stream().reduce(0L, Long::sum)

但它只给了我总字数,我在想是否有可能返回一个包含上述输出和所有字数的单个地图。

【问题讨论】:

  • 仅要求的问题通常不会在此站点上很好地收到。 SO 是针对特定的编程问题,关于已经存在的代码。如果有,请附上您当前的解决方案。
  • 而您已经尝试了 what 并被卡在 where 因为 something 不起作用?
  • 作为已经在 StackOverflow 上收集了 300 多个声誉的人,我很惊讶您没有意识到请求列表不是问题。请包括您的解决方案以及您在该解决方案中遇到的问题。
  • 小伙伴们我已经更新了,请检查..
  • 请删除保留标签我已经更新了我的问题

标签: java lambda java-8 java-stream


【解决方案1】:

如果我们只需要计算特殊字符和元音,我们可以这样使用:

Map<String,Long> result;
try(Stream<String> lines = Files.lines(path)) {
    result = lines
        .flatMap(Pattern.compile("\\s+")::splitAsStream)
        .flatMapToInt(String::chars)
        .filter(c -> !Character.isAlphabetic(c) || "aeiou".indexOf(c) >= 0)
        .mapToObj(c -> "aeiou".indexOf(c)>=0? "totalVowelCount": "totalSpecialCharacter")
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
}

首先,我们将行流扁平化为单词流,然后扁平化为字符流,按类型对它们进行分组。这很顺利,因为“特殊字符”和“元音”是互斥的。原则上,如果我们只是扩展过滤器以跳过空白字符,则可以省略对单词的展平,但在这里,它有助于解决计算单词的问题。

由于单词与字符是不同类型的实体,因此在同一操作中计算它们并不是那么简单。一种解决方案是为每个单词注入一个伪字符,并像最后的其他字符一样对其进行计数。由于所有实际字符都是正数,因此我们可以使用-1

Map<String,Long> result;
try(Stream<String> lines = Files.lines(path)) {
    result = lines.flatMap(Pattern.compile("\\s+")::splitAsStream)
        .flatMapToInt(w -> IntStream.concat(IntStream.of(-1), w.chars()))
        .mapToObj(c -> c==-1? "totalWordCount": "aeiou".indexOf(c)>=0? "totalVowelCount":
                Character.isAlphabetic(c)? "totalAlphabetic": "totalSpecialCharacter")
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
}

这会将"totalAlphabetic" 类别和其他类别添加到结果映射中。如果您不想这样,您可以在mapToObjcollect 步骤之间插入一个.filter(cat -&gt; !cat.equals("totalAlphabetic")) 步骤。或者在mapToObj 步骤之前使用第一个解决方案中的过滤器。

作为附加说明,这个解决方案做的工作比必要的多,因为它将输入分成几行,这不是必需的,因为我们可以像处理其他空格一样处理换行符,即作为单词边界。从 Java 9 开始,我们可以使用 Scanner 来完成这项工作:

Map<String,Long> result;
try(Scanner scanner = new Scanner(path)) {
    result = scanner.findAll("\\S+")
        .flatMapToInt(w -> IntStream.concat(IntStream.of(-1), w.group().chars()))
        .mapToObj(c -> c==-1? "totalWordCount": "aeiou".indexOf(c)>=0? "totalVowelCount":
                Character.isAlphabetic(c)? "totalAlphabetic": "totalSpecialCharacter")
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
}

这将首先将输入拆分为单词,而无需特别处理换行符。 This answer 包含与 Java 8 兼容的 Scanner.findAll 实现。

上述解决方案将每个既不是空格也不是字母的字符都视为“特殊字符”。如果您对“特殊字符”的定义不同,那么调整解决方案应该不会太难。

【讨论】:

    猜你喜欢
    • 2016-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-26
    • 1970-01-01
    • 2021-06-21
    • 1970-01-01
    相关资源
    最近更新 更多