个人项目 - WC

github项目地址:https://github.com/ScarletF6084/WC

项目相关要求

题目描述

Word Count
1. 实现一个简单而完整的软件工具(源程序特征统计程序)。
2. 进行单元测试、回归测试、效能测试,在实现上述程序的过程中使用相关的工具。
3. 进行个人软件过程(PSP)的实践,逐步记录自己在每个软件工程环节花费的时间。

WC 项目要求

wc.exe 是一个常见的工具,它能统计文本文件的字符数、单词数和行数。这个项目要求写一个命令行程序,模仿已有wc.exe 的功能,并加以扩充,给出某程序设计语言源文件的字符数、单词数和行数。

实现一个统计程序,它能正确统计程序文件中的字符数、单词数、行数,以及还具备其他扩展功能,并能够快速地处理多个文件。
具体功能要求:
程序处理用户需求的模式为:

wc.exe [parameter] [file_name]

 

基本功能列表:

wc.exe -c file.c     //返回文件 file.c 的字符数

wc.exe -w file.c    //返回文件 file.c 的词的数目  

wc.exe -l file.c      //返回文件 file.c 的行数


扩展功能:
    -s   递归处理目录下符合条件的文件。
    -a   返回更复杂的数据(代码行 / 空行 / 注释行)。

空行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”。

代码行:本行包括多于一个字符的代码。

注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:

    } //注释
在这种情况下,这一行属于注释行。

[file_name]: 文件或目录名,可以处理一般通配符。

高级功能:

 -x 参数。这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、行数等全部统计信息。

需求举例:  wc.exe -s -a *.c
返回当前目录及子目录中所有*.c 文件的代码行数、空行数、注释行数。

解题思路

1.对于字符数的统计,选择用File类的read()方法按字符读取文件,每读一次即为一个字符;

2.对于词数的统计,选择按字符读取文件,然后判别前一位字符和当前字符,若前一位字符为英文字符,当前字符不是英文字符,则词数+1;

3.对于行数的统计,可以使用BufferedReader类的readLine()方法按行读取文件,每读一次即为一行;但是为了方便一起统计,最后我选择了按字符读取文件,每遇到一个换行符行数+1;

特殊行

利用BufferedReader类的readLine()方法按行读取文件,以便利用正则表达式进行匹配特殊行

1.对于注释行,选择利用正则表达式进行匹配,若匹配到“//”则注释行数+1,若匹配到“/*”则进入标记状态,标记状态期间每读一行,注释行数+1,若匹配到“*/”则清除标记;

2.对于空白行,同样利用正则表达式进行匹配,若匹配到不含任何非空白字符的行,则空白行数+1;

3.对于代码行,依旧利用正则表达式进行匹配,若匹配到两个或以上的非空白字符,且该行不以任意数量的空白字符接“//”开头,则代码行数+1。

 

 

设计实现过程

流程图:

个人项目 - WC

开始时想根据输入的指令来决定计算对应的数据,然后输出,但是这样的话会导致每个对应方法都要读取一次文件,从而显得代码臃肿,所以最后决定在初始化类的时候就将数据统一计算出来,再根据指令输出需要的数据,故只设计了一个Counter类,一个构造方法进行初始化,以及将对应数据输出的print类。

关键代码

字符数、词数、行数的统计:

 1      //temp储存当前字符,wordFlag用于判断统计词数
 2         int temp, wordFlag = -1;
 3         path = filePath;
 4         FileReader fileReader = new FileReader(path);
 5         //按字符读取文件
 6         while ((temp = fileReader.read()) != -1){
 7             //统计字符数
 8             chars++;
 9             //统计词数,当英文字符后遇到非英文字符时,词数+1
10             if ((temp >= 'a' && temp <= 'z') || (temp >= 'A' && temp <= 'Z')) wordFlag = temp;
11             else if (temp != wordFlag && wordFlag != -1){
12                 words++;
13                 wordFlag = -1;
14             }
15             //统计行数,遇到一个换行符,行数+1
16             if (temp == '\n') lines++;
17         }

 

特殊行的统计:

 1         //统计注释行、空行和代码行
 2         BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(path)));
 3         int cflag = 0, starComments = 0;
 4         String lineTemp ;
 5         while ((lineTemp = br.readLine()) != null){
 6 //            System.out.println(lineTemp);
 7             //统计空白行
 8             Pattern pattern = Pattern.compile("\\S");       //不能含有任何非空白字符
 9             Matcher matcher = pattern.matcher(lineTemp);
10             if (!matcher.find()) blankLines++;
11             //统计注释行
12             Pattern pattern0 = Pattern.compile("//");       //单行注释,注释行数+1
13             Matcher matcher0 = pattern0.matcher(lineTemp);
14             if (matcher0.find()) commentLines++;
15 
16             Pattern pattern1 = Pattern.compile("/\\*");     //多行注释,从"/*"开始,直到遇到"*/"前,注释行数+1
17             Pattern pattern2 = Pattern.compile("\\*/");
18             Matcher matcher1 = pattern1.matcher(lineTemp);
19             Matcher matcher2 = pattern2.matcher(lineTemp);
20             if (matcher1.find()) cflag = 1;
21             if (cflag == 1) {
22                 commentLines++;
23                 starComments++;
24             }
25             if (matcher2.find()) cflag = 0;
26 
27             //统计代码行
28             pattern1 = Pattern.compile("\\S{2,}");  //非空白字符在两个或两个以上
29             pattern2 = Pattern.compile("^\\s*//");  //不能以任意数量的空白字符接"//"开头
30             matcher1 = pattern1.matcher(lineTemp);
31             matcher2 = pattern2.matcher(lineTemp);
32             if (matcher1.find() && !matcher2.find()) codeLines++;
33         }
34         codeLines -= starComments;                  //排除跨行注释的干扰

 

测试运行

空文件:

个人项目 - WC

 

只有一个字符的文件:

个人项目 - WC

 

 

 只有一个词的文件:

个人项目 - WC

 

 

 

只有一行的文件:

个人项目 - WC

 

 

 

典型源文件:

个人项目 - WC

 

 

个人项目 - WC

 

PSP

 

    PSP Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 30 30
Estimate 估计这个任务需要多少时间 10 15
Development 开发 360 360
Analysis 需求分析(包括学习新技术) 120 180
Design Spec 设计生成文档 10 10
Design Review 设计复审 (和同事审核设计文档) 5 5
Coding Standard 代码规范 (为目前的开发制定合适的规范) 15 10
Design 具体设计 60 90
Coding 具体编码 240 300
Code Review 代码复审 30 40
Test 测试(自我测试,修改代码,提交修改) 30 40
Reporting 报告 60 60
Test Report 测试报告 30 30
Size Measurement 计算工作量 10 10
Postmortem & Process Improvement Plan 事后总结,并提出新计划 30 30
Total 总计 1040 1210

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

项目小结

 本次项目在需求分析上花的时间有点多,所耗时间超出自己的预期不少,有些高估自己的能力,需要多锻炼一下自己的分析能力;

 在实现过程中也学习到了之前没怎么深入的正则表达式以及匹配,也算是小有收获。

 

上一篇:进阶指令


下一篇:个人项目 wc(C语言)