Java Scanner没有完全读取.txt中的每一行

时间:2014-09-11 16:13:23

标签: java file

该程序试图将文本文件分成单词,然后在每次使用每个单词时进行计数。扫描仪似乎只是读取每行的部分,我不知道为什么。这是我第一次使用这种扫描方法。

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;


public class WordStats {

    public static void main(String args[]){
        ArrayList<String> words = new ArrayList<>(1);
        ArrayList<Integer> num = new ArrayList<>(1);
        Scanner sc2 = null;
        try {
            sc2 = new Scanner(new File("source.txt"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();  
        }
        while (sc2.hasNextLine()) {
            Scanner s2 = new Scanner(sc2.nextLine());
            boolean set=false;
            while (s2.hasNext()) {
                num.add(1);
                String s = s2.next().replaceAll("[^A-Za-z ]", " ").toLowerCase().trim();
                for(int i=0;i<words.size(); i++){
                    if(s.equals(words.get(i))){
                        num.set(i,num.get(i)+1);
                        set=true;
                    }
                }
                if(!set){
                words.add(s);
                num.add(1);
                }
            }
        }
        for(int i=0;i<words.size();i++){
            System.out.println(words.get(i)+" "+num.get(i));
        }
    }
}

文本文件是葛底斯堡地址:

  

ABRAHAM LINCOLN,“GETTYSBURG ADDRESS”(1863年11月19日)

     八十年前,我们的父亲们提出了这个问题   大陆,一个新的国家,在自由中孕育,并致力于   所有人都是平等的命题。

     

现在我们正在进行一场伟大的内战,检验那个国家,   或任何如此构想和如此奉献的国家,都可以长久忍受。我们是   在那场战争的伟大战场上相遇。我们来奉献了一个   该领域的一部分,作为在这里的人的最后安息之地   献出了生命,那个国家可能会生活。它完全合适   我们应该这样做。

     

但是,从更广泛的意义上说,我们不能奉献 - 我们奉献 - 我们不能   神圣 - 这个地面。勇敢的人,无论是活着的还是死去的,都在挣扎着   在这里,已经将它奉为神圣,远远高于我们增加或减少的力量。   世界将很少注意到,也不记得我们在这里所说的,但它   永远不会忘记他们在这里做了什么。这对我们来说是生活,相反,   在这里献身于他们在这里战斗的未完成的工作   迄今为止如此高尚。我们宁愿来到这里   致力于摆在我们面前的伟大任务 - 来自这些   尊敬的死者,我们更加热爱他们的事业   给出了最后一个充分的奉献精神 - 我们在这里高度解决   这些死者不会白白死去 - 这个国家,在这之下   上帝,将有一个新的自由诞生 - 和那个政府   人民,人民,不为人民灭亡。

保留原始换行符。 我的输出似乎只计算每一行的一部分,并且还将空格作为单词计算两次。 输出:

abraham 1
lincoln 1
gettysburg 1
address 1
 2
november 1
fourscore 1
and 5
seven 1
years 1
ago 1
our 2
fathers 1
brought 1
forth 1
on 2
this 3
continent 1
a 7
new 2
nation 5
conceived 2
in 4
liberty 1
now 1
we 8
are 2
engaged 1
but 2

它可能不是扫描方法,但我对代码的这一部分比较熟悉,我认为不是这样。

3 个答案:

答案 0 :(得分:1)

问题是您的代码在循环的每次迭代中无条件地将1添加到num列表。这会使numwords相关,从而产生错误的输出。

从嵌套的num.add(1);循环中删除while可以解决问题。但是,更好的方法是使Map<String,Integer>跟踪计数。除了确保计数和单词始终处于同步状态之外,此更改还允许您完全删除嵌套的while循环,并根据您的地图算法使用快速查找。

答案 1 :(得分:1)

逻辑有点偏斜。您有并行列表,它们应具有相同数量的元素,但不会并行添加。

    Map<String, Integer> wordFrequencies = new TreeMap<>();

    while (sc2.hasNextLine()) {
        Scanner s2 = new Scanner(sc2.nextLine());
        while (s2.hasNext()) {
            String word = s2.next().replaceAll("[^A-Za-z ]", " ")
                .toLowerCase().trim();
            Integer n = wordFrequencies.get(word);
            wordFrequencies.put(word, n == null ? 1 : 1 + n);
        }
    }
    for (Map.Entry<String, Integer> entry : wordFrequencies.entrySet()) {
        System.out.printf("%-40s %5d%n", entry.getKey(), entry.getValue());
    }

答案 2 :(得分:1)

您需要在此while循环的开头重置布尔值

 while (s2.hasNext()) {
 set = false;

一旦您在每一行中遇到第一个重复的单词,则set始终为true,并且没有新单词添加到您的列表中。

空白计数是因为你的替代品如何处理&#34;(19&#34;和#34; 1863)&#34;因为那些&#34;单词&#34;。

中没有字母字符