WordCount--实现字符,单词,代码统计

Github:

            https://github.com/whoNamedCody/WordCount

PSP表格 

PSP2.1

PSP阶段

预估耗时

(分钟)

实际耗时

(分钟)

Planning

计划

            10            15

· Estimate

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

            20            20

Development

开发

           180            250

· Analysis

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

            10            30

· Design Spec

· 生成设计文档

            10            20

· Design Review

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

            20               20

· Coding Standard

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

            10             20

· Design

· 具体设计

            20             20

· Coding

· 具体编码

           100            150

· Code Review

· 代码复审

            20            30

· Test

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

            50           100

Reporting

报告

            20            40  

· Test Report

· 测试报告

            30            40

· Size Measurement

· 计算工作量

            10            10

· Postmortem & Process Improvement Plan

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

             5            15
 

合计

           515           780

需求说明:

          WordCount的需求可以概括为:对程序设计语言源文件统计字符数、单词数、行数,统计结果以指定格式输出到默认文件中,以及其他扩展功能,并能够快速地处理多个文件。

         1、基础功能:

              -c:输出字符,

              -l:输出代码行,

              -w:输出单词,

              -o:输出

         2、 扩展功能:

              -a:输出代码行/空行/注释行,

              -s:递归处理文件,

              -e:停用词表,

 

解题思路:

           1、java实现,但需要转成exe在cmd下输入命令执行,所以流程是:编码(.java)-->Export(.jar)-->exe4j(.exe)

           2、java里有static void main(String[] args),里面的args就是cmd下的命令数组,比如输入-c -l -w file.c(空格隔开),那么args数组长度为4

           3、对args数组进行遍历分析,找出输入命令和文件名,比如-c -l -w -a 后面跟的是输入文件名,-s后面会跟*.c之类的通配文件,-e后面会跟停用词表stoplist.txt,-o接输出文件result.txt

                这里识别出命令和文件后,会再对文件分析,比如-s  ./WordCount/*.c,需要截取出文件的上一层(相对)路径./WordCount和后缀.c,方便后续递归文件夹下的.c文件

           4、将所有的统计封装成一个函数:public void command(String[] args,String inputFile,String outputFile,WordCount WC)

           5、创建一个WordCount类,里面的属性有字符数,单词数,行数,代码行,空行,注释行,如果没有出现-s:则只实例化一个对象WordCount,调用一次command函数,输出前面的结果,如果出                           现 -s:即递归处理文件夹下面的*.c文件(当然*.txt,*.doc文件也是可以的),就声明多个WordCount对象,循环对对象属性进行赋值。如果需要输出就调用get和set方法获取属性值。

           6、递归处理文件:根据相对路径递归寻找文件夹下的后缀文件。

程序设计实现:

类:

                public class WordCount{}

函数方法设计:

        WordCount(int,int,int,int,int,int)是构造函数;get和set是MyEclipse自动生成的的getter和setter方法,main(string [ ])是程序入口,分析判断指令格式;command(String [ ],String,String,WordCount)执行指令,返回相应指令的统计值;wc(String,String)对输入文件进行统计;inStop(String,String[ ])判断单词是否在停用词表内;getFile(File)递归获取文件。

 

代码说明:

   1、执行命令:需要输出的有-c,-w,-l,-a,判断指令,直接暴力循环,优化日后再说。

 1 //命令执行,根据命令输出数据到屏幕和outputFile中    
 2     public void command(String[] args,String inputFile,String outputFile,WordCount WC)throws IOException{
 3         String outResult="";
 4         inputFile=inputFile.substring(inputFile.lastIndexOf("\\")+1, inputFile.length());
 5         for(int i=0;i<args.length;i++){
 6             if(args[i].equals("-c"))
 7                 outResult=outResult+inputFile+",字符数:" + WC.getCharCount()+"\r\n";
 8         }
 9         for(int i=0;i<args.length;i++){
10             if(args[i].equals("-w"))
11                 outResult=outResult+inputFile+",单词数:" + WC.getWordCount()+"\r\n";
12         }
13         for(int i=0;i<args.length;i++){
14             if(args[i].equals("-l"))
15                 outResult=outResult+inputFile+",行数:" + WC.getLineCount()+"\r\n";
16         }
17         for(int i=0;i<args.length;i++){
18             if(args[i].equals("-a"))
19                 outResult=outResult+inputFile+",代码行/空行/注释行:"+WC.getCodeCount()+","
20                         +WC.getSpaceCount()+","+WC.getNoteCount()+"\r\n";
21         }
22         //写数据到outputFile
23         System.out.println(outResult);        
24         File writename = new File(outputFile); 
25         writename.createNewFile(); 
26         BufferedWriter out = new BufferedWriter(new FileWriter(writename,true));
27         out.write(outResult);
28         out.flush();  
29         out.close(); 
30     }

 2、统计功能字符数、单词数、行数、代码行/空行/注释行 

      提一下代码行/空行/注释行

      匹配空行的正则表达式或则判断该行只有一个字符,则当前行为空行,匹配/*,如果存在,注释行++,标志进入注释行,继续匹配*/,如果不存在,注释行++,记下总共多少行,遇到*/,注释行++,标志结束注       
      释行,再匹配单行注释,其他的是代码行,最后计算注释的时候要减去只有/*没有 */的要加
 1 //统计功能字符数、单词数、行数、代码行/空行/注释行    
 2     public void wc(String inputFile,String stopFile) throws IOException{
 3         String lineString = null; 
 4         String[] buffer=null; //文件每行
 5         String[] buffer1 = null;//stoplist
 6        
 7         boolean isNote = false;
 8         int notNote=0;
 9         
10         //读取停用词表
11         if(useStop){
12             File dirr=new File(stopFile);
13             BufferedReader bff = new BufferedReader(new FileReader(dirr));
14             while((lineString=bff.readLine())!=null){
15               buffer1=lineString.split(",| ");
16             }
17             bff.close();    
18         }
19         lineString = null;
20         
21        // 读取输入文件inputFile
22         File dir=new File(inputFile);
23         BufferedReader bf = new BufferedReader(new FileReader(dir));         
24         while((lineString=bf.readLine())!=null){
25  
26              //遇到 , 空格 就结束赋值
27             buffer=lineString.split(",| ");
28             for(int i=0;i<buffer.length;i++){
29                 
30                 //使用停用词表则剔除词表内单词,不用则不踢
31                 if(useStop){
32                     if(!buffer[i].equals("")&&!inStop(buffer[i], buffer1)){
33                         wordCount++;
34                     }     
35                 }
36                 else{
37                     wordCount++;
38                 }
39                                
40             }
41             if(buffer.length!=1)
42                 lineCount++;
43             
44             charCount+=(lineString.length()+1);
45             
46             
47             lineString=lineString.trim();
48             //空行,一个字符的也算空行
49             if (lineString.matches("^[//s&&[^//n]]*$")||lineString.length()==1) {  
50                 spaceCount++;      
51             } 
52             //注释/*的开始
53             else if (lineString.startsWith("/*") && !lineString.endsWith("*/")||((lineString.startsWith("{/*")
54                     ||lineString.startsWith("}/*"))&&!lineString.endsWith("*/"))){
55                  noteCount++;
56                  isNote=true;
57              }
58             //没有遇到*/
59             else if(isNote&&!lineString.endsWith("*/")&&!lineString.startsWith("*/")) {  
60                 notNote++;
61                 noteCount++;
62             }
63             //遇到*/
64             else if (isNote == true && (lineString.endsWith("*/")||lineString.startsWith("*/"))) {
65                 noteCount++;
66                 isNote=false;
67             }
68             //注释行
69             else if (lineString.startsWith("//")|| lineString.startsWith("}//")||lineString.startsWith("{//")||
70                     ((lineString.startsWith("{/*") ||lineString.startsWith("}/*")||lineString.startsWith("/*"))
71                             && lineString.endsWith("*/"))) { 
72                 noteCount++;
73             }
74             else{
75                 codeCount++;
76             }            
77             }
78             bf.close();
79             noteCount-=notNote;
80             codeCount+=notNote;
81     }
3、每次判断单词是否在停用词表内
 1 //判断是否在停用词表内
 2 public static boolean inStop(String str,String[] buffer){
 3     int count=0;
 4     for(int i=0;i<buffer.length;i++){
 5         if(str.equals(buffer[i])){
 6             count++;
 7         }
 8     }
 9     if(count>0)
10         return true;
11     else
12         return false;
13 }

4、遍历文件目录,如-s ./test/*.c则递归遍历./test目录下的.c文件

 1 //遍历目录文件    
 2     public static List<File> getFile(File dir) {  
 3         List<File> files = new ArrayList<File>();
 4         // 此文件下的所有文件和文件夹集合
 5         File[] subs = dir.listFiles();   
 6         for (File file : subs) {  
 7             if (file.isFile() && file.getName().endsWith(endStr)) {
 8                 // 把获取到的后缀文件添加到集合中,可以是任何后缀文件  
 9                 files.add(file); 
10             } else if (file.isDirectory()) 
11                 //如果是目录,就进行递归
12                 files.addAll(getFile(file));   
13         }  
14         return files;  
15     }   

 

测试设计过程:

    设计测试用例的思路是采用白盒测试的语句覆盖,尽可能把测试用例覆盖所有可能的程序语句,当然特别是分支语句,会多做测试,如-s的是否递归处理文件在我的程序中是一个分支语句

      基本功能:

      1、测试-c:输出file.c字符数

            wc.exe -c file.c  

 

       2、测试-c、-w、-l:输出file.c字符数,单词数、行数 (当前根目录)   

           wc.exe -c -w -l file.c

  

       3、测试-w 、-l 、-c:输出./testFile/file.c 字符数,单词数、行数 (根目录下其他路径,命令顺序)

           wc.exe -w -l -c ./testFile/file.c 

   

       4、测试-c 、-l 、-w、-o:输出file.c字符数,单词数、行数、输出到文件resultAdd.txt

            wc.exe -c -l -w file.c -o resultAdd.txt

 

   

      扩展功能:

         5、测试-a:输出file.c的代码行/空行/注释行

              wc.exe -a file.c

         6、测试-s、-a:输出根目录下所有.c文件的代码行/空行/注释行

              wc.exe -s -a *.c

      

          7、测试-e:测试停用词表stoplist.txt

              wc.exe -w file.c -e stoplist.txt 

  

          8、测试-c、-w、-l 、-a、-o:输出file.c字符数,单词数、行数 、代码行/空行/注释行输出到result.txt

              wc.exe -c -w -l -a file.c -o result.txt

   

         9、测试-a、-s、-e:测试递归,代码行/空行/注释行,停用词表stoplist.txt 

           wc.exe -a -s ./testFile/*.c -e stoplist.txt

 

        10、测试-c、-w、-l、-a、-e、-o:对不递归进行测试

            wc.exe -c -w -l -a file.c -e stoplist.txt -o result.txt

 

        11、测试-c、-w、-l、-a、-s、-e、-o:覆盖所有的指令测试

  

 

测试脚本

         点击testScript.exe可以执行完11个测试用例,类似于批处理的方式,但只有一个进程,批处理测试用例。

          下面是java代码,简单叙述一下思路:创建一个进程打开之前的wc.exe,逐行读取测试用例testCase.txt,一行是一条测试用例。

 

 1 package test;
 2 import java.io.BufferedInputStream;
 3 import java.io.BufferedReader;
 4 import java.io.File;
 5 import java.io.FileReader;
 6 import java.io.IOException;
 7 import java.io.InputStreamReader;
 8 import java.util.Scanner;
 9 
10 public class TestScript {
11          //进程p
12         static Process p;
13     public static void main(String[] args) throws IOException{
14         String lineString=null;
15         File dirr=new File("testCase.txt");  //测试用例文件
16         if(dirr.exists()){
17             BufferedReader bff = new BufferedReader(new FileReader(dirr));
18             while((lineString=bff.readLine())!=null){
19                 //非空行执行测试用例
20                 if(!lineString.trim().matches("^[//s&&[^//n]]*$")){
21                     System.out.println(lineString);
22                     command(lineString);
23                 }       
24             }
25             bff.close();
26         }else{
27             System.out.println("没有该测试文件");
28         }
29         
30         Scanner sc = new Scanner(System.in);
31         String scc=sc.nextLine();
32     }
33     
34     public static void command(String cmd){
35         Runtime run = Runtime.getRuntime();//返回与当前 Java 应用程序相关的运行时对象  
36         try {  
37             p = run.exec(cmd);// 启动另一个进程来执行命令  
38             BufferedInputStream in = new BufferedInputStream(p.getInputStream());  
39             BufferedReader inBr = new BufferedReader(new InputStreamReader(in));  
40             String lineStr;  
41             while ((lineStr = inBr.readLine()) != null)   
42                 System.out.println(lineStr);  
43             if (p.waitFor() != 0) {  
44                 if (p.exitValue() == 1)
45                     System.err.println("命令执行失败!");  
46             }  
47             inBr.close();  
48             in.close();  
49         } catch (Exception e) {  
50             e.printStackTrace();  
51         }  
52     }
53     
54 }

 参考链接:

                      https://www.baidu.com

                      https://i.cnblogs.com/

                      https://bbs.csdn.net/

                      https://github.com/

 

 

 

posted @ 2018-03-20 23:32  Who_Named_Cody  阅读(2234)  评论(1编辑  收藏  举报