【问题标题】:(Java) Trying to read a txt file and count the number of occurrences for each word(Java)试图读取一个txt文件并计算每个单词的出现次数
【发布时间】:2021-03-20 09:05:39
【问题描述】:

我应该编写一个程序来读取名为 mobydick.txt 的文件。该文件包含《白鲸记》这本书的全文。 The mobydick.txt file looks like this

我必须读取文件,显示文件中的每个唯一单词,然后显示每个唯一单词的出现次数。

输出应如下所示:

字数

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 看起来很奇怪。

这很奇怪,因为如果我为像this 这样更小更简单的文本文件运行相同的代码,输出看起来像exactly like I want it to

mobydick.txt 我做错了什么?

【问题讨论】:

  • 使用 HashMap
  • 您使用什么 IDE?我认为这很重要。我认为扫描仪没有读取 UTF-8 的东西(顺便说一句:你有 Top、mid、jug 和 bot...但是没有 sup?)
  • 请不要只将结果/数据/代码发布为图片。看起来您的输入文件存在字符编码问题。

标签: java counter word


【解决方案1】:

只看文本输入文件。例如,它包含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 会给你两个标记:以前和从不。

您仍应将输入小写,扫描仪无法为您执行此操作。

设置分隔符:

scanner.useDelimiter("\\W+"); // double backslash. That's not a typo.

编辑:这个答案之前使用了[^a-zA-Z]+,但正如@VGR 在评论中指出的那样,\\W+ 更容易理解;一般来说,它可能更惯用。

【讨论】:

  • "\\W+" 的模式对于刚接触正则表达式的人来说可能更容易理解。
  • @VGR 是的,你可能是对的。我会更新答案
最近更新 更多