WordCount项目总结

Posted meow

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WordCount项目总结相关的知识,希望对你有一定的参考价值。

Github项目地址:https://cannotfindtheid.github.io/WordCount/

 

PSP表格

PSP2.1

PSP阶段

预估耗时

(小时)

实际耗时

(小时)

Planning

计划

 1  1

· Estimate

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

 1  1

Development

开发

 23  29

· Analysis

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

 2  2

· Design Spec

· 生成设计文档

 2  

· Design Review

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

 1  

· Coding Standard

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

 1  1

· Design

· 具体设计

 3  3

· Coding

· 具体编码

 10  15

· Code Review

· 代码复审

 1  3

· Test

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

 3  5

Reporting

报告

 4  2

· Test Report

· 测试报告

 2  2

· Size Measurement

· 计算工作量

 1  

· Postmortem & Process Improvement Plan

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

 1  
 

合计

 28  32

解题思路:

刚开始看到需求时,我的第一个疑问就是:以前我们接触到的都是直接在程序中得到参数,或者通过键盘输入得到参数,而这次却是通过命令行传参数。那么,获得参数之后要怎么进行解析、调用对应函数、向各个函数中传参呢?

于是我开始在网上查找命令行参数解析的方法,并在博客[1]中了解到了一些命令行选项解析工具,并决定使用Commons-cli。

大致了解后,我开始思考如何实现各个功能。这些都将在程序设计和代码实现中详细说明,这里略过。

然后我了解了一下jar包的生成和exe文件的生成过程,包括jre环境的设置,这里参考了博客[2]。

程序设计实现过程:

程序共包含三个类,在同一个Main包下:

Count类:

私有成员属性:字符数、单词数、行数、代码行数、空行数、注释行数,都有其get方法;

parse方法:解析给定文件,并给各成员属性赋值

  (如果指定了停用词表,调用stop方法,得到所有停用词,在计算单词数时不参与)

stop方法:由给出的停用词表名,得到所有的停用词并封装到一个ArrayList中

FileChoose类:

chooseFile方法:显示文件选择图形界面,获取所选的文件的绝对路径

outputToFile方法:将一个ArrayList<String>输出到指定文件

findFile方法:找到指定文件夹下所有符合条件的文件的绝对路径

showResult方法:用图形界面显示结果

Main类:

成员变量:parseFilename,要进行解析的文件名

main函数:进行命令行解析并调用响应函数。先解析出各option对应的参数,由于-c、-w、-l、-a、-s共用一个参数,要先得到optionValue值不为空的值,并赋给parseFilename;当parseFilename不为空时,对此文件进行解析,并调用Count类中相应属性的get方法,得到其值,并加入一个ArrayList中。对-o、-x、-s,也是调用相应方法。

代码说明:

(1)Count.parse函数:用BufferedReader.readLine()按行读取并解析文件,得到字符数、单词数、行数、详细行数

 1 public void parse(String name,ArrayList<String> stopList){
 2         String s;
 3         String wordSplit1[]=null;
 4         String wordSplit2[]=null;
 5         char c1;
 6         char c2 = 0;
 7         FileReader fr=null;
 8         BufferedReader br=null;
 9         try {
10             fr=new FileReader(new File(name));
11             br=new BufferedReader(fr);
12             int flag3=0;//多行注释行
13             
14             //计算单词数
15             while((s=br.readLine())!=null){
16                 if(flag3==2)flag3=0;
17                 
18                 //空格分割的单词组
19                 wordSplit1=s.split(" ");
20                 for(int i=0;i<wordSplit1.length;i++){
21                     //得到多个单词
22                     wordSplit2=wordSplit1[i].split(",");
23                     wordNum+=wordSplit2.length;
24                     
25                     for(int j=0;j<wordSplit2.length;j++){
26                         if(wordSplit2[j].equals(""))wordNum--;
27                         
28                         if(stopList!=null)
29                             for(int k=0;k<stopList.size();k++)
30                                 //如果有禁用列表中的或空字符串,不算单词数
31                                 if(!stopList.get(k).equals("")&&wordSplit2[j].equals(stopList.get(k)))wordNum--;
32                         
33                     }
34                 }
35                 
36                 //计算各行数
37                 lineNum++;
38                 charNum+=s.length();
39                 int flag1=0;//此行可看做代码的字符数
40                 int flag2=0;//判断是否有单行注释
41                 
42                 
43                 //按行解析
44                 for(int i=0;i<s.length();i++){
45                     c1=s.charAt(i);
46                     
47                     if(i<=s.length()-2&&c1!=44){
48                         c2=s.charAt(i+1);
49                         //此字符和后一个字符为“//”,为单行注释
50                         if(c1==47&&c2==47)flag2=1;
51                         //多行注释开始
52                         if(c1==47&&c2==42)flag3=1;
53                         //多行注释结束
54                         if(c1==42&&c2==47)flag3=2;
55                         }
56                     if(flag2==0)flag1++;
57                     }
58                 
59                 //得到此行类型
60                 if(flag3!=0)noteLine++;
61                 else if(flag1==0||flag1==1){
62                     if(flag2==0)blankLine++;
63                     if(flag2==1)noteLine++;
64                 }
65                 else codeLine++;
66             }
67             
68             
69         } catch (Exception e) {
70             // TODO Auto-generated catch block
71             e.printStackTrace();
72         }finally{
73             try {
74                 br.close();
75                 fr.close();
76             } catch (IOException e) {
77                 // TODO Auto-generated catch block
78                 e.printStackTrace();
79             }
80             
81         }
82     }

(2)选择文件的图形界面和显示结果的图形界面

 1 public class FileChoose {
 2 
 3     //图形界面选择文件
 4     public String chooseFile(){
 5         JFileChooser jfc=new JFileChooser();
 6         jfc.setDialogTitle("请选择一个文件");
 7         jfc.showOpenDialog(null);
 8         jfc.setVisible(true);
 9         
10         //得到用户选择的文件路径
11         String filename=jfc.getSelectedFile().getAbsolutePath();
12         return filename;
13     }
 1 public void showResult(ArrayList<String> content){
 2         JFrame jf=new JFrame("统计结果");
 3         jf.setSize(500, 300);
 4         jf.setLocation(500, 400);
 5         jf.setVisible(true);
 6         //关闭时释放内存
 7         jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 8         //文本域
 9         JTextArea jta=new JTextArea();
10         jf.add(jta);
11         
12         for(int i=0;i<content.size();i++){
13             jta.append(content.get(i)+"\n");
14         }

(3)将字符串列表输出到指定文件:

 1 public void outputToFile(String filename,ArrayList<String> content){
 2         FileWriter fw = null;
 3         
 4         try {
 5             fw=new FileWriter(filename);
 6             for(int i=0;i<content.size();i++){
 7                 fw.write(content.get(i));
 8             }
 9             
10         } catch (IOException e) {
11             // TODO Auto-generated catch block
12             e.printStackTrace();
13         }finally{
14             try {
15                 fw.close();
16             } catch (IOException e) {
17                 // TODO Auto-generated catch block
18                 e.printStackTrace();
19             }
20         }
21     }

(4)找到文件夹下所有符合的文件(文件名用绝对路径):

 1     public void findFiles(String upperFile,ArrayList<String> fileNames,String matchName){
 2         File f=new File(upperFile);
 3         File[] files;
 4         //如果是文件夹
 5         if(f.isDirectory()){
 6             //获取所有子文件
 7             files=f.listFiles();
 8             String absolutePath;
 9             //判断每个子文件是文件还是文件夹
10             for(int i=0;i<files.length;i++){
11                 absolutePath=files[i].getAbsolutePath();
12                 
13                 //如果是文件且后缀匹配
14                 if(files[i].isFile()&&absolutePath.endsWith(matchName.substring(1))){
15                     fileNames.add(absolutePath);
16                 }
17                 //如果是文件夹,则继续查找
18                 else if(files[i].isDirectory())
19                     findFiles(absolutePath,fileNames,matchName);
20             }
21         }
22     }

(5)main函数,解析命令行并调用各函数:

  1 public static void main(String[] args) {
  2         DefaultParser parser=new DefaultParser();
  3         CommandLine cl=null;
  4         
  5         //定义选项
  6         Options options=new Options();
  7         
  8         options.addOption(Option.builder("c").optionalArg(true).numberOfArgs(1).build());//统计字符数
  9         options.addOption(Option.builder("w").optionalArg(true).numberOfArgs(1).build());//统计单词数
 10         options.addOption(Option.builder("l").optionalArg(true).numberOfArgs(1).build());//统计行数
 11         options.addOption(new Option("o",true,"OUTPUTFILE"));//输出到指定文件
 12         options.addOption(Option.builder("s").optionalArg(true).numberOfArgs(1).build());//递归处理目录下所有文件
 13         options.addOption(Option.builder("a").optionalArg(true).numberOfArgs(1).build());//更复杂的数据(代码行、空行、注释行)
 14         options.addOption(new Option("e",true,"STOPLIST"));//停用词表
 15         options.addOption(new Option("x","CHOOSEFILE"));//图形界面选取文件
 16         
 17         try {
 18             //解析命令行
 19             cl=parser.parse(options, args);
 20             ArrayList<String> content = new ArrayList<String>();
 21             FileChoose fileChoose=new FileChoose();
 22             String str;
 23             Count count=new Count();
 24             
 25             //有-x
 26             if(cl.hasOption("x")){
 27                 parseFilename=fileChoose.chooseFile();
 28                 count.parse(parseFilename, null);
 29                 
 30                 content.add(parseFilename+",字符数:"+count.getCharNum()+"\r\n");
 31                 content.add(parseFilename+",单词数:"+count.getWordNum()+"\r\n");
 32                 content.add(parseFilename+",行数:"+count.getLineNum()+"\r\n");
 33                 content.add(parseFilename+",代码行/空行/注释行:"+count.getCodeLine()+"/"+count.getBlankLine()+"/"+count.getNoteLine()+"\r\n");
 34                 fileChoose.showResult(content);
 35             }
 36                 
 37             else if(!cl.hasOption("x")){
 38                 //无-x时
 39                 int c=0,w=0,l=0,a=0,s=0,e=0;
 40                 ArrayList<String> files;
 41                 ArrayList<String> stopList = new ArrayList<String>();
 42                 
 43                 //检查各option,得到参数(解析文件名)
 44                 if(cl.hasOption("c")){
 45                     c=1;
 46                     if((str=cl.getOptionValue("c"))!=null)parseFilename=str;
 47                 }
 48 
 49                 
 50                 if(cl.hasOption("w")){
 51                     w=1;
 52                     if((str=cl.getOptionValue("w"))!=null)parseFilename=str;
 53                 }
 54                 
 55                 if(cl.hasOption("l")){
 56                     l=1;
 57                     if((str=cl.getOptionValue("l"))!=null)parseFilename=str;
 58                 }
 59                 
 60                 if(cl.hasOption("a")){
 61                     a=1;
 62                     if((str=cl.getOptionValue("a"))!=null)parseFilename=str;
 63                 }
 64                 
 65                 if(cl.hasOption("s")){
 66                     s=1;
 67                     if((str=cl.getOptionValue("s"))!=null)parseFilename=str;
 68                 }
 69                 
 70                 if(cl.hasOption("e")){
 71                     e=1;
 72                     String stopListFile=cl.getOptionValue("e");
 73                     stopList=count.stop(stopListFile);
 74                 }
 75                 
 76                 if(parseFilename!=null){
 77                     files=new ArrayList<String>();
 78                     
 79                     //如果有-s,files为所有文件,如果无-s,files只有parseFilename一个文件
 80                     if(s==1){
 81                         //file表示根目录
 82                         File file=new File("");
 83                         fileChoose.findFiles(file.getAbsolutePath(), files, parseFilename);    
 84                     }
 85                     else{
 86                         files.add(parseFilename);
 87                     }
 88                     
 89                     
 90                     for(int i=0;i<files.size();i++){
 91                         
 92                         //根据是否有停用词表,进行解析
 93                         if(e==1){
 94                             //有停用词表
 95                             count.parse(files.get(i), stopList);
 96                         }
 97                         else{
 98                             //无停用词表
 99                             count.parse(files.get(i), null);
100                         }
101                         
102                         //有-c
103                         if(c==1){
104                             int charCount=count.getCharNum();
105                             content.add(files.get(i)+",字符数:"+charCount+"\r\n");
106                         }
107                         
108                         //有-w
109                         if(w==1){
110                             int wordCount=count.getWordNum();
111                             content.add(files.get(i)+",单词数:"+wordCount+"\r\n");
112                         }
113                         
114                         //有-l
115                         if(l==1){
116                             int lineCount=count.getLineNum();
117                             content.add(files.get(i)+",行数:"+lineCount+"\r\n");
118                         }
119                         
120                         //有-a
121                         if(a==1){
122                             content.add(files.get(i)+",代码行/空行/注释行:"+count.getCodeLine()+"/"+count.getBlankLine()+"/"+count.getNoteLine()+"\r\n");
123                         }
124                     }
125                     
126                     
127                     //有-o
128                     if(cl.hasOption("o")){
129                         if((str=cl.getOptionValue("o"))!=null)
130                             fileChoose.outputToFile(str, content);
131                     }
132                     else fileChoose.outputToFile("result.txt", content);
133                 }
134             }
135             
136             
137             
138             
139             
140                 
141         } catch (ParseException e) {
142             // TODO Auto-generated catch block
143             e.printStackTrace();
144         }
145         
146         
147     }

测试过程设计:

测试用例:

(1)需要解析的文件

 1 #include<stdio.h>
 2 void transfer(int n)
 3 {
 4     if (n > 10)transfer(n / 10);
 5     printf("%c", 0 + n % 10);
 6 }
 7 void main()
 8 {
 9     int n;
10     printf("Please input a number:\n");
11     scanf("%d", &n);
12     transfer(n);
13 }//this is a noteLine
14 
15 void show(){
16 
17     ;
18     ;/*noteLine
19      
20      hello,this is noteLine
21      right?
22      */
23     ;//me too
24 }

可以看出,此文件中有空白行、前面单字符的注释行、仅有一个可见字符的行、多行注释行、代码行、多行注释中的空行等可能导致高风险的情况。

(2)wc.exe -c -w -l -a filename

测试-c、-w、-l、-a功能是否正常,即能否输出正确数据到默认“result.txt”文件

(3)wc.exe -a -l -c -w filename

打乱顺序,看输出到文件中的顺序是否依然不变

(4)wc.exe -c filename -o outputname

是否能输出到指定文件

(5)wc.exe -o outputname

未指定解析的文件时,无法输出

(6)wc.exe -c filename -o

未指定要输出到的文件名,无法输出

(7)wc.exe -a -c -s *.txt

能否得到根目录及其子目录下所有符合“*.txt”的文件并输出正确结果

(8)wc.exe -x

单独使用-x

(9)wc.exe -x -c filename

使用-x后又使用-c,也不会将结果输出到文件

(10)wc.exe -w filename -e stoplistfile

停用词列表是否对生效

(11)wc.exe -c -a -l filename -e stoplistfile

停用词列表是否会对其他数据有影响

 

参考文献链接:

[1]http://rensanning.iteye.com/blog/2161201

[2]http://blog.csdn.net/sunkun2013/article/details/13167099

 

以上是关于WordCount项目总结的主要内容,如果未能解决你的问题,请参考以下文章

wordCount开发与测试总结

回归 | js实用代码片段的封装与总结(持续更新中...)

Hadoop学习笔记:WordCount程序的实现与总结

项目开发收尾总结(片段)

hadoop 学习笔记-2wordcount 完整实例

WordCount