zoukankan      html  css  js  c++  java
  • 词频统计单元测试

      我这次用构造单词树的形式进行词频统计,此次的任务是对已有的程序进行单元测试。选用的工具是JUnit。它是基于测试驱动开发(TDD)原理的。 

      此次词频统计的主体思想是,每次读入文章中的128(自己设定)个字符(目的是防止溢出),将这些字符存储到一颗树中,树中的节点有一个存储词频的变量和一个指向子节点的数组(类似于c语言中的指针)。最后遍历整棵树,按照词频进行排序。

    下面是我的片段代码

    下面这段代码是定义的节点的结构

    class CharTreeNode{
        int count=0;
        CharTreeNode children[]=new CharTreeNode[26];
    }

    下面这段代码是全局变量的声明,因为涉及到建树时都是从根节点开始生成,所以根节点定义为全局变量

    //设置为全局变量,每读入一行,在原来生成的树的基础上继续生成子节点
        public static CharTreeNode root=new CharTreeNode();
        public static CharTreeNode p=root;
        private static FileReader reader=null;
        private static BufferedReader buffer=null;
        private Scanner scan;

    下面这段代码实现的是对每个输入的字符串进行树的构造,最后返回的是树的根。

    /*
         * 生成单词树
         * */ 
        public static CharTreeNode generateCharTree(String text) {
            char c = ' ';
            for (int i = 0; i < text.length(); i++) {
                c = text.charAt(i);
                if (c > 'A' && c < 'Z') {
                    c = (char) (c + 'a' - 'A'); // 变大写字母为小写字母
                }
                if (c >= 'a' && c <= 'z') {
                    if (p.children[c - 'a'] == null) {
                        p.children[c - 'a'] = new CharTreeNode();
                    }
                    p = p.children[c - 'a'];
                } else {
                    p.count++;
                    p = root;
                }
            }
            if (c >= 'a' && c <= 'z')
                p.count++;
            return root;
        }

    下面这段代码用方法重载的形式遍历整棵树,然后将遍历到的单词存储在List

        /*
         * 遍历整棵树,将遍历得到的每个单词存到list中
         * */ 
        public static void searchTree(List<Word> list, CharTreeNode node, char buffer[], int len) {
            for (int i = 0; i < 26; i++) {
                if (node.children[i] != null) {
                    buffer[len] = (char) (i + 'a');
                    if (node.children[i].count > 0) { // 遍历到了单词的最后一个字母
                        Word word = new Word();
                        word.setNum(node.children[i].count);
                        word.setWord(String.valueOf(buffer, 0, len + 1));
                        list.add(word);
                    }
                    searchTree(list, node.children[i], buffer, len + 1); // 递归调用,每次以上一个叶节点作为下次递归的头结点
                }
            }
        }
    
        /*
         * searchTree()为重载的方法
         * */ 
        public static void searchTree(List<Word> list, CharTreeNode node) {
            searchTree(list, node, new char[100], 0);
        }

    下面这段代码是对不同路径构造的树数进行单词的排序和输出

    /*
         * 对文章用generateCharTree()函数生成单词树,在对生成的单词树进行排序并且输出
         */
        public static void sortAndOutput(String filePath) throws IOException {
            reader = new FileReader(filePath);
            buffer = new BufferedReader(reader);
            char c[] = new char[128]; // 防止读入一行太长而出现溢出的情况
            int len;
            String temp = ""; // 存储buffer读出的字符
            String lastWord = ""; // 若读出的最后一个字符是字母,lastWord存储那个字符所在的单词,lastWord就被加到下一轮的temp中
            while ((len = buffer.read(c)) > 0) {
                temp = ""; // 清空上一轮temp的内容
                temp += lastWord;
                for (int i = 0; i < len; i++) {
                    temp += c[i];
                }
                lastWord = ""; // 清空上一轮lastword的内容
                if (Character.isLetter(c[len - 1])) { // 当128个字符的最后一个字符为字母时,就得分情况讨论
                    int j, t;
                    for (j = len - 1, t = 0; Character.isLetter(c[j]); j--, t++)
                        ; // t代表最后一个字符(c[len-1])为字符时,前面有几个连续的字符
                    temp = temp.substring(0, temp.length() - t); // 当检测到最后一个字符为字母时,直接将最后一个字符所在的单词剔除本轮的temp,而转接到下一轮的temp中
                    for (int k = j + 1; k < len; k++) {
                        lastWord += c[k];
                    }
                }
                root = generateCharTree(temp);
            }
            List<Word> list = new ArrayList<Word>();
            searchTree(list, root);
            // 对生成的单词树按照单词的次数逆向排序排序
            Collections.sort(list, new Comparator<Object>() {
                @Override
                public int compare(Object o1, Object o2) {
                    Word word1 = (Word) o1;
                    Word word2 = (Word) o2;
                    return word2.getNum() - word1.getNum();
                }
            });
            buffer.close();
            reader.close();
            root=new CharTreeNode();  //但对于输入的是目录时,对每篇文章建立的树统计完后,应当初始化这棵树,便于下篇文章建树
            System.out.println("单词	数量");
            for (int i = 0; i < 5; i++) {
                System.out.println(((Word) list.get(i)).getWord() + "	" + ((Word) list.get(i)).getNum());
            }
        }

    下面进入此次的重头戏:单元测试。引入Junit后在每个测试的方法前加上@Test,选中方法名即可测试

    下面这段代码是对输入目标的文件的路径进行该文件的词频统计

    @Test
        public void testInputFilePath() throws IOException {
            scan = new Scanner(System.in);
            String filePath = scan.next();
            while (filePath != null) {
                sortAndOutput(filePath);
                filePath = scan.next();
            }
        }

    结果截图如下

          

    下图当输入的文件名找不到时

    下面这段代码是对输入目标文件的文件名进行该文件的词频统计

    @Test
        public  void testInputFileName() throws IOException {
            scan = new Scanner(System.in);
            String filePath = scan.next();
            sortAndOutput("F:\document\" + filePath);
        }

    结果截图如下

    下面这段代码是对输入目标文件所在的目录名,进行该文件的词频统计

    @Test
        public void testInputDirectoryPath() throws IOException {
            scan = new Scanner(System.in);
            String DirectoryPath = scan.next();
            File f = new File(DirectoryPath);
            File s[] = f.listFiles();
            for (int i = 0; i < s.length; i++) {
                String fileName = s[i].getName();
                if (fileName.endsWith(".txt")) {
                    sortAndOutput(DirectoryPath + "\" + fileName);
                }
            }
        }

    结果截图如下

    下面这段代码测试重定向输入

    @Test
        public void reDirectInputByConsole() throws IOException {
            Scanner scan = new Scanner(System.in);
            String command = scan.nextLine();
            String filePath = command.substring(command.indexOf("<") + 1);
            reader = new FileReader(filePath.trim());
            buffer = new BufferedReader(reader);
            String line = null;
            line = buffer.readLine();
            String targetFile = "F:\document\new.txt";
            FileWriter out = new FileWriter(targetFile);
            while (line != null) {
                out.write(line + "
    ");
                line = buffer.readLine();
            }
            out.close();
            buffer.close();
            reader.close();
            sortAndOutput(targetFile);
        }
    }

    结果如下

    测试后的感受:

     测试过程中发现了程序的bug,比如在测试输入目录时,因为没将数进行清空,下一篇文章的单词会追加到以前的树上,通过单元测试解决了这个问题。

  • 相关阅读:
    sublime打开txt文件乱码的问题
    while循环小例
    mongoDB内置文档定义
    WebStorm 10.0.3注册码
    angularjs之ng-mode获取lobject类型里的键值
    前端打印console
    js去掉数组的空字符串
    js数组去重的三种方式的比较
    js数据类型之判断
    Bootstrap中的datetimepicker浅谈
  • 原文地址:https://www.cnblogs.com/liquan/p/5904068.html
Copyright © 2011-2022 走看看