我有一个文本文件,我想检查
-文件中的单词总数
-文件中的元音总数
-文件中的特殊字符总数
使用Java 8流。
如果可能的话,我希望在一次迭代中将其输出为Map,即
{"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)
但是它只给我总的字数,我在想是否有可能返回一个包含以上所有输出的单张地图。
答案 0 :(得分:2)
如果我们只需要计算特殊字符和元音,则可以使用以下内容:
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"
类别。如果不希望这样,可以在.filter(cat -> !cat.equals("totalAlphabetic"))
和mapToObj
步骤之间插入一个collect
步骤。或在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包含Scanner.findAll
的Java 8兼容实现。
上述解决方案将既不是空格也不是字母的每个字符都视为“特殊字符”。如果您对“特殊字符”的定义不同,则适应解决方案应该不太困难。