Q re Java Program从文本文件中读取,创建一个arraylist,重新格式化并输出到另一个文件

时间:2015-01-20 17:14:46

标签: java

作为一名java学生(初学者)我刚刚完成了编写程序以执行以下任务的任务:

  1. 阅读文本文件的内容;

  2. 挑出文本中的所有字词,将所有大写字母替换为小写字母;

  3. 生成文本中出现的单词的字典(即按字母顺序排列的单词列表,每行一个单词,不重复);
  4. 将字典输出到另一个文件。
  5. 我们被建议有一个包含main方法的类,并使用ArrayList,Scanner,PrintWriter和FileReader类。

    我设法做了下面的工作,但是它提出了一些问题/基本差距。

    我相信基于良好O.O.的原则。编程实践中,我应该将下面的内容分解为一系列具有单一目的的方法,然后调用这些方法。但是,我真的很难做到这一点。任何人都可以详细说明/建议一种改进特定点的方法吗?如果我错了,还是纠正我?

    public class Main
    {
    
        private static ArrayList<String> dictionary; 
        private static ArrayList<String> tempdictionary;
    
        public static void main() throws FileNotFoundException
        {
            Scanner inFile = new Scanner(new FileReader("H:\\csc8001\\results.txt"));
            dictionary = new ArrayList <>();
            tempdictionary = new ArrayList <>();
    
            while (inFile.hasNext()) { 
                dictionary.add(inFile.next().toLowerCase().replaceAll("[^a-zA-Z ]", ""));
            }
            inFile.close();
    
            PrintWriter outFile = new PrintWriter("H:\\csc8001\\results1.txt");
            int index = 0;
            for (String a : dictionary)
            {
                if (!tempdictionary.contains(a)){ 
                    tempdictionary.add(a);
                } else {
                    index++;
                }
            }
    
            Collections.sort(tempdictionary);
            for (int i=0; i<tempdictionary.size(); i++)
                outFile.println(tempdictionary.get(i));
            outFile.flush();
            outFile.close();
        }
    
    }
    

3 个答案:

答案 0 :(得分:1)

正如其他人所说,你的代码绝对没有错,因为它代表你已经给出的任务。但是你已经表达了对面向对象原则的兴趣,所以我有一些可能有用的想法。注意 - 以下内容对于对特定任务采取过于笼统的方法的批评是非常开放的 - 关于此问题有perennial debate,许多人订阅了"You ain't gonna need it"学校。

为什么面向对象的方法是合适的?

如果您可能需要具有相同类但具有不同属性值的多个副本,则面向对象的方法将非常有用。在您指定的任务中,情况并非如此。

然而,可以想象,你可能想要在一个后续任务中从(一个)其他文件创建一个字典,或者在同一个程序中使用多个文件编写一个程序。

在这种情况下,对象的构成是什么?

在此任务中,系统会要求您创建字典。字典可以是一个对象。你可以从这个起点接近任务。例如:

public class Dictionary
{
}

词典有什么作用?按字母顺序排序的单词列表。正如其他人所说的那样,一个很好的选择是使用SortedSet(习惯于查看API documentation a.k.a javadocs,他们是你的基本朋友),但你被告知使用{{1这就是我们要做的。

ArrayList

您可以继续添加方法来执行每项任务。就个人而言,我可能有一个构造函数采用public class Dictionary { ArrayList<String> words; } 文件名。我已将文件的读取直接写入此内容 - 您可以同样调用一个私有方法(例如String)来获取文件并提取单词。

parseFile()

然后我添加一个removeDuplicates()方法(我上面已经调用过) - 有很多方法可以做到这一点。你可以像你一样使用临时的ArrayList - 我将举一个我怀疑更快的例子。

public Dictionary(String inputFilename) throws FileNotFoundException 
{
    Scanner inFile = new Scanner(new FileReader(inputFilename));
    words = new ArrayList <String>();

    while (inFile.hasNext()) { 
        words.add(inFile.next().toLowerCase().replaceAll("[^a-zA-Z ]", ""));
    }
    inFile.close();

    removeDuplicates();

    Collections.sort(words);
}

最后 - 添加private void removeDuplicates() { HashSet<String> dupSet = new HashSet<String>(); dupSet.addAll(words); words.clear(); words.addAll(dupSet); } 方法

writeToFile(String outFilename)

你被告知要把你的课程放在主,所以这样做。现在可能很短:

public void writeToFile(String outFilename) throws FileNotFoundException
{
    PrintWriter outFile = new PrintWriter(outFilename);
    for (int i=0; i<words.size(); i++)
        outFile.println(words.get(i));
    outFile.flush(); // strictly redundant
    outFile.close();
}

你获得了什么?

您现在拥有一个Dictionary类,您可以将其导入任何项目并按上述方式使用。如果下周的任务是“修改你的字典程序,为这个目录中的所有100个文件制作一个字典”,你就笑了。您还可以向Dictionary类添加函数(例如 public static void main(String[] args) throws FileNotFoundException { d = new Dictionary("H:\\csc8001\\results.txt"); d.outputToFile("H:\\csc8001\\results1.txt"); } ),同时相信您不会破坏现有函数或使用这些函数的任何程序。

你失去了什么?

15分钟读完这个答案。是时候编写一些可能永远不会使用的方法。原始程序非常简洁,本质上是一个脚本。

轻微风格的东西

打电话给你的班级mergeWith(Dictionary d2)是很不寻常的。没有错,但即使你没有采用上面的字典对象方法,我也会重命名它 - 只要它有主要方法,它仍然可以运行。

你真的不需要tempdictionary - 你可以'unquify'并排序Main - 从而避免保留带有重复项的未排序列表(以及它使用的相关内存)

初始化PrintWriter看起来有点不寻常,然后进行一些处理(使列表唯一并排序),然后输出。倾向于尽可能地将文件打开到您输出的位置,然后尽快再次关闭它。

答案 1 :(得分:0)

总的来说,你的概念是正确的;想想DRY原则(不要重复自己)。如果您不得不多次编写该代码,请将其粘贴在函数中并调用它。

然而,在这种情况下,写主要的所有代码是&#34; OK&#34;因为程序没有太多 - 你的代码已经符合DRY要求。如果你必须阅读多个文件,那么你绝对应该将代码放入函数而不是像那样的主函数。

如果你真的想要分解它,你可以做一些事情,就像将while (inFile.hasNext())块放在它自己的函数中一样,你将扫描仪对象作为参数传递。

答案 2 :(得分:0)

我没有看到任何特别值得制作单独方法的东西。但我确实对代码有一些评论,没有特别的顺序:

  1. 为什么使用静态类变量而不是局部变量?

  2. index变量的目的是什么?

  3. 为什么要在打开和写入输出文件之间对集合进行排序/过滤?

  4. 关闭作家也会刷新它,因此无需明确调用flush()

  5. 为什么不使用SortedSetTreeSet作为您的收藏品,您可以完全避免排序和过滤?例如:

    Scanner inFile = new Scanner(new FileReader("H:\\csc8001\\results.txt"));
    SortedSet<String> dictionary = new TreeSet<>();
    
    while (inFile.hasNext()) { 
        dictionary.add(inFile.next().toLowerCase().replaceAll("[^a-zA-Z ]", ""));
    }
    inFile.close();
    
    PrintWriter outFile = new PrintWriter("H:\\csc8001\\results1.txt");
    for (String s : dictionary)
        outFile.println(s);
    outFile.close();