WordCount

github地址:https://github.com/szc1506/WC

一.PSP表格

PSP2.1

PSP阶段

预估耗时

(分钟)

实际耗时

(分钟)

Planning

计划

 15  25

· Estimate

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

 30  30

Development

开发

 280  350

· Analysis

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

 100  120

· Design Spec

· 生成设计文档

 50  60

· Design Review

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

 30  20

· Coding Standard

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

 20  30

· Design

· 具体设计

110 80

· Coding

· 具体编码

 300  450

· Code Review

· 代码复审

 60  60

· Test

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

 200  180

Reporting

报告

 150  220

· Test Report

· 测试报告

 120  150

· Size Measurement

· 计算工作量

 30  25

· Postmortem & Process Improvement Plan

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

 60  45
 

合计

 1555  1845

二.需求说明

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

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

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

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

wc.exe -o outputFile.txt  //将结果输出到指定文件outputFile.txt

wc.exe -s            //递归处理目录下符合条件的文件

wc.exe -a file.c   //返回更复杂的数据(代码行 / 空行 / 注释行)

wc.exe -e stopList.txt  // 停用词表,统计文件单词总数时,不统计该表中的单

三.程序实现过程

   第一次拿到题目时限定语言是java,因为本身对java不是很熟悉,就花了较多的时间在熟悉java和配环境上。参考链接:http://www.runoob.com/java/java-environment-setup.html。题目描述要求统计文件中的字符数,先读入文件,然后字符数,单词数,行数这三个可以一起统计,因为可以一次读一行。扩展功能中的各种代码行,注释行可以用正则式来匹配,递归处理文件夹下文件可以写一个递归函数,停用词表可以先读出所有停用词,放到数组里,然后匹配所有单词,匹配则不用加一。找资料的过程大概就是JAVA的各种使用方法,文末已经给出链接。

四.代码说明

1.字符计数:每读入一个字符,判断是不是回车换行符,不是则字符计数器加一

package java86;
import java.io.*;
import java.util.*;
public class Javatest {
    public static int countC(String fn) {//统计字符数
        BufferedReader reader = null;
        int res = 0;
        try {
            reader = new BufferedReader(new FileReader(fn));
            String str = null;
            while ((str = reader.readLine()) != null) {
                res += str.length();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return res;
    }

2.单词统计:按字符流读取文件,对每一个字符做判断,如果不是换行符或空格则继续往下读取;当读取到换行符或者空格是,将前面读到的字符拼作一个单词,单词计数加一

public static int countW(String fn, List<String> list) {//统计单词数目
        BufferedReader reader = null;
        int res = 0;
        try {
            reader = new BufferedReader(new FileReader(fn));
            String str = null;
            while ((str = reader.readLine()) != null) {
                String[] temp = str.split(" |,");
                for (String s : temp) {
                    if (s != null && !list.contains(s)) {
                        ++res;
                    }
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return res;
    }

3.行数读取调用java API,统计计数

public static int countL(String fn) {//统计行数
        BufferedReader reader = null;
        int res = 0;
        try {
            reader = new BufferedReader(new FileReader(fn));
            String str = null;
            while ((str = reader.readLine()) != null) {
                ++res;
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return res;
    }

4.扩展功能

递归获取文件:获取文件目录,判断是不是目录,如果是目录则递归获取该目录下的内容;如果符合要求的文件,则先将文件名存储,与之后的执行一同进行

代码行,注释行,空行的统计。

对于单词数、字符数、行数的统计:

package text1;
import java.io.*;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.regex.Pattern;
public class extendedFun {
    //递归处理该目录下的同类型文件
    static void allfile(String[] list){
        int lenth=list.length;
        String myfile=null;
        myfile=list[lenth-1];
        if(lenth==8)
              myfile=list[3];    
        File directory = new File("");//参数为空
        String courseFile;
        try {
            courseFile = directory.getCanonicalPath();//获取当前目录路径
             // 获得指定文件对象  
            File file = new File(courseFile);   
            // 获得该文件夹内的所有文件   
            File[] array = file.listFiles();   
            File afile=new File(myfile); 
            String fileName=afile.getName();    
            String fileTyle=fileName.substring(fileName.lastIndexOf("."),fileName.length()); //获取文件类型
            for(int i=0;i<array.length;i++)
            {   
                if(array[i].isFile())//如果是文件
                {   
                    if(array[i].getName().endsWith(fileTyle)){
                        if(lenth==2){
                        if(list[0].equals("-l")||list[0].equals("-c")||list[0].equals("-w"))
                                basecount.count(list[0],array[i].getName());
                        else if(list[0].equals("-a")){
                            moredata(array[i].getName(),null);
                        }
                        }
                        else if(lenth==3&&(list[0].equals("-l")||list[0].equals("-c")||list[0].equals("-w"))&&(list[1].equals("-l")||list[1].equals("-c")||list[1].equals("-w"))){
                            basecount.count(list[0],list[1],array[i].getName());
                        }
                        else if(lenth==4){
                            basecount.count(list[0],list[1],list[2],array[i].getName());
                        }
                        else if(lenth==8)
                        {
                            if(list[0].equals("-a")){
                            basecount.count(list[1], array[i].getName(),list[7]);
                            basecount.count(list[2], array[i].getName(),list[7]);
                            moredata(array[i].getName(),list[7]);
                            stopcount(array[i].getName(),list[5],list[7]);
                            }                  
                        }
                        else System.out.println("输入格式错误");
                    }
                }
            }   
        } catch (IOException e) {
            e.printStackTrace();
        }    
    }
    //统计代码行/空行/注释行
    static void moredata(String myfile,String outfile)throws FileNotFoundException {  
        if(outfile==null)
            outfile="result.txt";
        String sfile=new String(myfile);
         File file=new File(sfile);
         // 记录注释行数  
         long annotationLine = 0;  
        // 记录空白行数  
        long blankLine = 0;  
        // 记录有效代码的行数  
        long codeLine = 0;   
        //假注释
        long notLine=0;
        if (file == null || !file.exists())   
            throw new FileNotFoundException(file + ",文件不存在!"); 
        BufferedReader br = null;  
        // 判断此行是否为注释行  
        boolean comment = false;  
        int whiteLines = 0;  
        int commentLines = 0;  
        int normalLines = 0;       
        try {  
            br = new BufferedReader(new FileReader(file));  
            String line = "";  
            while ((line = br.readLine()) != null) {  
                line = line.trim();  
                if (line.matches("^[//s&&[^//n]]*$")||line.equals("{")||line.equals("}")) {  
                    // 空行 :本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”
                    whiteLines++;      
                } 
               /* 本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:
                *  }//注释
                */
                else if (line.startsWith("/*") && !line.endsWith("*/")||((line.startsWith("{/*")||line.startsWith("}/*"))&&!line.endsWith("*/"))){
                    // 判断此行为"/*"开头的注释行  
                    commentLines++;  
                    comment = true;  
                } else if (comment == true && !line.endsWith("*/")&&!line.startsWith("*/")) {  
                    // 为多行注释中的一行(不是开头和结尾)
                    notLine++;
                    commentLines++;  
                } else if (comment == true && (line.endsWith("*/")||line.startsWith("*/"))) {  
                    // 为多行注释的结束行  
                    commentLines++;  
                    comment = false;  
                } else if (line.startsWith("//")|| line.startsWith("}//")||line.startsWith("{//")||
                            ((line.startsWith("{/*") ||line.startsWith("}/*")||line.startsWith("/*")) && line.endsWith("*/"))) {  
                    // 单行注释行  
                    commentLines++;  
                } else {  
                    // 正常代码行  
                    //System.out.println(line);
                    normalLines++;  
                }  
            }        
        } catch (FileNotFoundException e) {  
            e.printStackTrace();  
        } catch (IOException e) {  
            e.printStackTrace();  
        } finally {  
            if (br != null) {  
                try {  
                    br.close();  
                    br = null;  
                } catch (IOException e) {  
                    e.printStackTrace();  
                }  
            }  
            try{
                 //打开一个写文件器,构造函数中的第二个参数true表示以追加形式写文件
                FileWriter writer = new FileWriter(outfile, true);
                char[] message=(myfile+",代码行/空行/注释行:"+(normalLines+notLine)+"/"+whiteLines+"/"+(commentLines-notLine)+"\r\n").toCharArray();//换行"\r\n"不是"\n"
                writer.write(message);
                 writer.close();
             }
             catch(IOException e){
                 System.out.println("File read/write Error"+e);
             }
        }  
    } 
    //调用停用词表,重写统计单词数
    static void stopcount(String thefile,String txt,String output){
        int stopcount=0;
        int wordcount=0;
        File stopfile=new File(txt);
         File file=new File(thefile);
        ArrayList<String> stop=new ArrayList<String>(3);
        
//       读入stopfile.txt的单词到一个动态string数组中保存    
         if(stopfile.exists()){
             try{
                 FileInputStream fis=new FileInputStream(stopfile);
                 InputStreamReader isr=new InputStreamReader(fis,"UTF-8");
                 BufferedReader br=new BufferedReader(isr);
                 String line=new String("");
                 StringBuffer sb=new StringBuffer();
                  TreeMap<String, Integer> map = new TreeMap<>(); 
                 String[] split =null;
                 while((line=br.readLine())!=null){
                      sb.append(line);
                     split = line.split("\\s+");  
                    for (int i = 0; i < split.length; i++) {  
//                        获取到每一个单词  
                          Integer integer = map.get(split[i]);  
//                        如果这个单词在map中没有,赋值1  
                          if(null==integer){  
                              map.put(split[i], 1);  
                          }
                      }  
                 }         
                 Set<String> keySet = map.keySet();  
                  for (String string : keySet) {  
                      stop.add(string);    
                  }
                 br.close();
                 isr.close();
                 fis.close();
             }
             catch(FileNotFoundException e){
                 e.printStackTrace();
             }
             catch(UnsupportedEncodingException e){
                 e.printStackTrace();
             }
             catch(IOException e){
                 e.printStackTrace();
             }
             
         }

         //统计stop表的总数目
         if(file.exists()){
             try{
                 FileInputStream fis=new FileInputStream(file);
                 InputStreamReader isr=new InputStreamReader(fis,"UTF-8");
                 BufferedReader br=new BufferedReader(isr);
                 String line=new String("");
                 StringBuffer sb=new StringBuffer();
                  TreeMap<String, Integer> map = new TreeMap<>(); 
                 while((line=br.readLine())!=null){
                     String[] split = line.split("\\s++|\\.|,|\\;|\\(|\\)|\\[|\\]|\\<|\\>|\\=|\\-|\\+|\\*|\\/|\\{|\\}");  //去除多个空格\\s+
                     for (int i = 0; i < split.length; i++) {                     
//                       获取到每一个单词  
                         Integer integer = map.get(split[i]);  
//                       如果这个单词在map中没有,赋值1  
                         if(null==integer){  
                             map.put(split[i], 1);  
                         }else{  
//                           如果有,在原来的个数上加上一  
                             map.put(split[i], ++integer);  
                         }  
                     }  
                 }
//               遍历,根据key获取所对应的value  
                 Set<String> keySet = map.keySet();  
                 for (String string : keySet) { 
                     int i=0;
                     if(!(string.equals(""))){
                     wordcount+=map.get(string);
                 while(i<stop.size()){
                        if(string.equalsIgnoreCase(stop.get(i++)))//不区分大小写判断
                    { 
                             stopcount+=map.get(string);
                             //System.out.println(string+":"+map.get(string));  
                        }}
                        
               }
                 } 
                 //System.out.println(wordcount+"  "+stopcount+"  "+(wordcount-stopcount));
                 sb.append(line);
                 br.close();
                 isr.close();
                 fis.close();
                 
             }
             catch(FileNotFoundException e){
                 e.printStackTrace();
             }
             catch(UnsupportedEncodingException e){
                 e.printStackTrace();
             }
             catch(IOException e){
                 e.printStackTrace();
             }
         }
         try{
            //打开一个写文件器,构造函数中的第二个参数true表示以追加形式写文件
             if(output==null)
                 output="output.txt";
            FileWriter writer = new FileWriter(output, true);
            char[] message=(thefile+", 单词数(停用后):"+(wordcount-stopcount)+"\r\n").toCharArray();//换行"\r\n"不是"\n"
            writer.write(message);
             writer.close();
        }
        catch(IOException e){
            e.printStackTrace();
        }
    }
} 

五.测试过程

测试过程对于每一项功能单独测试,再进行组合测试,确保覆盖了所有可执行的代码,对文件名输入文件和文件夹也作出了测试,总共设计10个测试用例:

(1)wc.exe -l ../test/test.c -o out1.txt                                (2)wc.exe -w ../test/test.c -o out2.txt

(3)wc.exe -a ../test/test.c -o out3.txt                               (4)wc.exe -c ../test/test.c -o out4.txt

(5)wc.exe -l -w -a -c ../test/test.c -o out5.txt                   (6)wc.exe -a ../test/ -o out6.txt

(7)wc.exe -a -s ../test/ -o out7.txt                                    (8)wc.exe -a ../test/*.c -o out8.txt

(9)wc.exe -a ../test/*.c -e ../stop.txt -o out9.txt                (10)wc.exe -l -w -a -c -s ../test/ -e ../stop.txt -o out10.tx

六.总结 

   软件测试工作是一个系统而复杂的工程,软件测试的目的就是确保软件的质量、确认软件以正确的方式做了你所期望的事情,所以工作的主要任务是发现软件的错误、有效定义和实现软件成分由底层到高层的组装过程、验证软件是否满足规格书要求和系统定义文档所规定的技术要求、为软件质量模型的建立提供依据。
    而且软件的测试不仅是要确保软件的质量,还要给开发人员提供信息,以方便其为风险评估做相应的准备,以及为其提供分析依据,重要的是要贯穿在整个软件开发的过程中,保证整个  软件开发的过程是高质量的。 软件测试对测试工程师来讲,要求具备较强的专业知识,严谨细心耐心的测试态度,良好的反向思维、发散思维能力、沟通能力等等。

部分代码参考1504班成建伟

六.参考链接

1. http://www.cnblogs.com/winterfells/p/7965596.html

2. http://www.runoob.com/java/java-environment-setup.html

3.https://stackoverflow.com/questions/25555717/intellij-idea-javafx-artifact-build-does-not-generate-exe

4. http://blog.csdn.net/daxiang_zhang/article/details/2149896

5. http://blog.csdn.net/hpchenqi_16/article/details/48504111

6. http://blog.csdn.net/alex__0805/article/details/50895222

7.https://bbs.csdn.net/topics/390567815

 

posted @ 2018-03-20 21:52  !champion!  阅读(190)  评论(1编辑  收藏  举报