第2周个人作业:WordCount编码和测试

github地址:https://github.com/ryan-sgy/WordCount

一.PSP表格

 

PSP2.1

PSP阶段

预估耗时

(分钟)

实际耗时

(分钟)

Planning

计划

 10  30

· Estimate

· 估计这个任务需要多少时间

10 10

Development

开发

 4天  5天

· Analysis

· 需求分析 (包括学习新技术)

 1天  1天

· Design Spec

· 生成设计文档

 -  -

· Design Review

· 设计复审 (和同事审核设计文档)

 -  -

· Coding Standard

· 代码规范 (为目前的开发制定合适的规范)

 20  30

· Design

· 具体设计

 120  200

· Coding

· 具体编码

 3天  3天

· Code Review

· 代码复审

 100  100

· Test

· 测试(自我测试,修改代码,提交修改)

 100  130

Reporting

报告

 30  30

· Test Report

· 测试报告

 30  30

· Size Measurement

· 计算工作量

 120  60

· Postmortem & Process Improvement Plan

· 事后总结, 并提出过程改进计划

 60  30
 

合计

11天  11天

二.解题思路

首先,使用的语言是Java,已经快一年没有使用了,先检查了一下jdk环境,简单的到网上了解了一下Java的各种使用方法,还好语言都是相通的,也逐渐回忆清楚Java的语言模式。

统计文件的字符数,单词数和行数,根据命令输出相应结果。具体操作如下:

  1. 接到用户输入,依次判断输入是否符合格式,并提取输入的关键内容,例如参数和路径,并根据参数设置相应的标志变量。
  2. 调用readFile函数,传进去所需要统计的文件路径,函数中根据标志变量的值进行相应的输出,同时将输出结果写入content,为了使有 -o参数时,可以传入相应的内容。
  3. 统计字符数,等于读入的字符串数+行数(使用readline会使每一行少一个字符)。
  4. 统计单词数,使用split("( |,)+")匹配逗号和空格的组合并将读入的文件字符串分开成字符串数组,数组的length即为单词数。
  5. 统计行数,每次readline即加一行。
  6. 输出文件,只需将输出结果时已经得到的content作为参数传入writeFile函数写到相应的文件即可,相应的文件路径从一开始的用户输入得到。

三.程序设计实现过程

因为功能比较简单,所以我就把所有的功能都写在一个类里面了,首先是基本功能,记录行数,词数和字符数,我写了lineCount(),wordCount()和charCount()三个函数来实现.至于-o输出到指定文件.,只需在main函数里做个判断就好了.然后就是扩展功能,首先是-s实现递归目录下符合条件的文件,我写了个searchFile()函数来实现,主要涉及到正则表达式和遍历时,对其是文件还是文件夹的判断的处理,然后是-a 返回更复杂的数据(代码行/空行/注释行)我用了一个otherCount()函数来实现,这个的难点在于读懂(代码行/空行/注释行)的定义,把各种情况考虑到了代码就很容易写了,-e就比较简单了包含这个参数,就去读它后面的文件,把停用词表包含在一个List。

四.代码说明

空行和不包含注释符号的代码行容易判断,包含注释符号的代码行稍稍复杂,通过split方法获得注释符号之前或之后的子串,再通过正则匹配判断其中是否含有代码,若有则该行仍为代码行,最后剩下的就是注释行。

public static int kindOfLine(String line){ //-1 empty 1 code 0 note
        String temp ="";
        if(line.trim().length() == 0)
            return -1;
        if(!line.contains("//") && !line.contains("/*") && !line.contains("*/"))  //不含这些符号必是code
            return 1;
        if(line.contains("//"))                                                   // //之前的code
            temp = line.split("//")[0];
        if(line.contains("/*"))                                                   // /*之前的code
            temp = line.split("/\\*")[0];
        if(line.contains("*/"))                                                   // */之后的code
            temp = line.split("\\*/")[line.split("\\*/").length - 1];
        if(temp.matches(".*\\w+.*"))                                      // 含有字母或数字则该行是code
            return 1;
        return 0;
    } 

构造函数接受File作为参数,通过BufferedReader每次读取一行,最终拼接成一个字符串,将其转换为字符数组,统计其长度可得字符数;按照题目对于单词的定义,将字符按照空格或逗号进行分割,统计分割后的非空字符串数即为单词数;调用kindOfLine获得行数信息。
构造函数重载接收file和stopList作为参数,统计单词数时剔除stopList中含有的单词。

public WordCount(File file) {
        BufferedReader bf;
        try {
            bf = new BufferedReader(new FileReader(file));
            String temp1, temp2 = "";
            while((temp1 = bf.readLine()) != null) {
                temp2 += temp1 + String.valueOf('\n');
                line++;                                         // 获取行数
                int i = kindOfLine(temp1);                      // 获取行数详细信息
                if(i == -1)
                    emptyLine++;
                else if(i == 1)
                    codeLine++;
                else
                    noteLine++;
                for (String val: temp1.split(" |,")){
                    wordNum += val.equals("") ? 0 : 1;          // 非空单词数
                }
            }
            buffer = temp2.toCharArray();
            bf.close();
            charNum = buffer.length - 1;                        // 字符数
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

public WordCount(File file, HashSet<String> stopList)
// 根据输入进行判断并进行输出
for
(File val : fileList) { String name = val.getName(); if(val.equals(stopFile) || val.equals(outputFile)){ continue; } if(isE){ wc = new WordCount(val, stopList); } else{ wc = new WordCount(val); } if(isC){ output = output + name + ",字符数: " + wc.getCharNum() + "\r\n"; } if(isW){ output = output + name + ",单词数: " + wc.getWordNum() + "\r\n"; } if(isL){ output = output + name + ",行数: " + wc.getLine() + "\r\n"; } if(isA){ output = output + name + ",代码行/空行/注释行: " + wc.getCodeLine() + "/" + wc.getEmptyLine() + "/" + wc.getNoteLine() + "\r\n"; } } BufferedWriter out = new BufferedWriter(new FileWriter(new File(curPath + "\\result.txt"))); out.write(output); out.flush(); out.close(); if(isO){ outputFile.createNewFile(); // 创建新文件 out = new BufferedWriter(new FileWriter(outputFile)); out.write(output); // \r\n即为换行 out.flush(); // 把缓存区内容压入文件 out.close(); // 关闭文件 }

五.测试过程设计

白盒的测试用例需要做到:
  ·保证一个模块中的所有独立路径至少 被使用一次
  ·对所有逻辑值均需测试 true 和 false
  ·在上下边界及可操作范围内运行所有循环
  ·检查内部数据结构以确保其有效性

设计以下10个测试用例(第一行为文件名,第二行为操作命令,之后为文件的内容):

//test1.c
//wc.exe -a test1.c
int
//test2.txt
//wc.exe -a -l -w -c test2.txt -o output.c
int
//test3.c
//wc.exe -a D:\test3.c
int
//test4.c
//wc.exe -a test4.java
int
//test5.c
//wc.exe -a test5.*
int
//test6.c
//wc.exe -a test6.c
int
}//

/*
//test7.c
//wc.exe -a -l -w -c  test7.c -e stop.txt
int,void
//test8.c
//wc.exe -a -l -w -c -s  test8.c -e stop.txt
int,void
{//
//test9.c
//wc.exe -a -l -w -c -s  *.c -e stop.txt
int,void
/*
//test10.c
//wc.exe -a -l -w -c -s  *.c -e stop.txt -o D:\output.txt
int,void
*/ main

结果:正确的测试用例都有正确的输出,错误的测试用例wc.exe会提示相应错误信息。

 

六.参考链接 

posted @ 2018-03-20 23:33  西西光光  阅读(169)  评论(2编辑  收藏  举报