[英](Java) Trying to read a txt file and count the number of occurrences for each word
我应该编写一个程序来读取名为 mobydick.txt 的文件。 该文件包含《白鲸记》这本书的全文。 mobydick.txt 文件看起来像这样
我必须读取文件,显示文件中的每个唯一单词,然后显示每个唯一单词的出现次数。
output 应如下所示:
字号
43
鲸鱼 12
船 93
到目前为止,这是我的代码:
import java.util.*;
import java.io.*;
public class Main
{
public static void main(String[] args) throws IOException
{
//Create input stream & scanner
FileInputStream fin = new FileInputStream("mobydick.txt");
Scanner fileInput = new Scanner(fin);
//Create Arraylist
ArrayList<String> words = new ArrayList<String>();
ArrayList<Integer> count = new ArrayList<Integer>();
//Read through file and find the words
while(fileInput.hasNext())
{
//Get next word
String nextWord = fileInput.next();
//Determine if the word is in the arraylist
if(words.contains(nextWord))
{
int index = words.indexOf(nextWord);
count.set(index, count.get(index) + 1);
}
else
{
words.add(nextWord);
count.add(1);
}
}
//close
fileInput.close();
fin.close();
System.out.println("WORDS COUNT");
//Print out the results
for(int i = 0; i < words.size(); i++)
{
System.out.print(words.get(i) + " " + count.get(i) + "\n");
}
}
}
然而,当我运行这段代码时,我得到了一个奇怪的output 。
这很奇怪,因为如果我为这样一个更小更简单的文本文件运行相同的代码,output 看起来就像我想要的一样。
我在 mobydick.txt 上做错了什么?
只需查看文本输入文件。 例如,它包含ago-never
。 程序员的计算机工具往往非常愚蠢,因为我们程序员需要它们非常简单。 扫描仪在空白处拆分。 时期。 -
不是空格。 Scanner 尽职尽责地为您提供ago-never
作为单一令牌。 如果书中包含Cosmic said: "Sheesh, this coding stuff is hard, man.".
,那么这些是扫描仪将为您提供的令牌:
Cosmic
said:
"Sheesh,
this
coding
stuff
is
hard,
man!".
这显然不是你想要的。 你想要例如man
。 不是man.".
第二个问题是文本文件是文件,因此是bag-o-bytes。 字节不是字符。 所以,当你把你的文件变成扫描仪时,你隐含地要求计算机对如何做到这一点进行猛烈抨击,而且它会:它将使用“平台默认编码”,这是 java-ese 用于'从来没有你想要的'。 这里没有简单的答案。 有人需要调查或告诉你编码是什么。 可能是 UTF-8。 在这种情况下,你必须告诉 java:
new Scanner(fin, "UTF-8")
你没有,所以 java 选择了“平台默认编码”,这是一些随意且通常错误的选择,因此像“Haägen Dasz”这样的东西会搞砸 - 只有最基本的字符往往会在使用错误字符集编码的转换中幸存下来。
至于如何解决第一个问题,您可能真正需要的只是告诉扫描仪您希望“令牌之间的东西”是“任意数量的非字母”。 定界符是一个正则表达式,它可能是一个你还没有学过的概念; 这很复杂。 正则表达式\W+
表示:“1 个或多个'非单词'字符”的概念,并且作为分隔符意味着感叹号、引号、点、换行符的序列 - 都作为分隔标记的事物而消失。 - 也不是字母,因此,输入文件中的ago-never
将给您两个标记:ago 和 never。
您仍然应该将输入小写,扫描仪无法为您执行此操作。
要设置分隔符:
scanner.useDelimiter("\\W+"); // double backslash. That's not a typo.
编辑:这个答案以前使用过[^a-zA-Z]+
,但正如@VGR 在评论中指出的那样, \\W+
更容易理解; 一般来说,它可能更惯用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.