第二周个人作业WordCount

GitHub项目地址 https://github.com/husterC/WordCount

一.PSP表格

PSP2.1

PSP阶段

预估耗时

(分钟)

实际耗时

(分钟)

Planning

计划

 15  15

· Estimate

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

 5  5

Development

开发

   

· Analysis

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

 60  70

· Design Spec

· 生成设计文档

 -  -

· Design Review

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

 -  -

· Coding Standard

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

 -  -

· Design

· 具体设计

 60  60

· Coding

· 具体编码

 240  300

· Code Review

· 代码复审

 60  120

· Test

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

 60  90

Reporting

报告

 -  -

· Test Report

· 测试报告

 -  -

· Size Measurement

· 计算工作量

 15  10

· Postmortem & Process Improvement Plan

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

 20  30
 

合计

 8h55min  11h40min

二.解题思路

对于基本功能而言:

  1.首先需使用Java数据输入输出流相关类对文件进行读写。

  2.编写函数实现各个指令中对所读取文件的操作,返回结果数值。

  3.需要使用main函数中的args参数来传递指令,对应不同指令执行不同操作。

对于扩展功能而言:

  1.对于-s指令,完成函数:检查当前地址,如果是文件,就直接进行相应操作,如果是文件夹,则遍历该文件夹,对该文件夹目录下的所有内容进行递归调用处理。

  2.对于-a指令,主要是注释行和代码行的区分会产生问题,先利用换行划分为不同的行,然后取注释行的flag,如果满足要求,则为注释行,如果不满足要求,则为代码行。

  3.对于-e指令,先读取相应文件中的内容并划分为停用词和单词,再来判断单词是否与停用词相等,对于文件中每一个与停用词相同的单词,单词计数减一。

  4.对于*匹配的情况,获取*外的文件部分作为判断标准,获取文件前面的部分作为地址,或是取项目的默认地址。然后识别满足要求的文件,对满足条件的文件进行指令操作。

三.程序设计实现过程

  (补充)

  程序设计说明:整个程序我是按照功能模块来划分的函数,也就是说不同指令对应是由不同的函数实现,最后在main函数中获取指令内容,然后进行指令判断,如果存在某个指令,比如-l,那么就调用实现-l功能的函数执行统计行数的功能,如此进行,待到遍历完所有命令内容后,同时统一完成输出。

 

  具体函数与重要变量及其功能如下:

  public static ArrayList<String> Path = new ArrayList<String>();   //用于存放操作文件路径

 

  public static ArrayList<String> Name = new ArrayList<String>();   //用于存放操作文件名

 

  public static int c(String FilePath){           //实现读取字符个数的功能

    输入文件路径,返回该文件中所含有的字符数

 

  public static int w(String FilePath){               //实现读取单词个数的功能

    输入文件路径,返回该文件中所含有的单词数

 

  public static int l(String FilePath){          //实现读取文件行数功能

    输入文件路径,返回该文件中所含有的行数

 

  public static int[] a(String FilePath){          //实现读取空行,代码行,和注释行行数的功能。

    输入文件路径,返回int型数组,其中包含空行,代码行,和注释行的行数

 

  public static int e(String FilePath,String StopFile){      //实现读取除停用词以外单词的个数的功能

    输入目标文件路径和停用词文件的文件路径,返回除停用词外单词个数

 

  public static boolean output(String Str,String FilePath){   //实现输出字符串到指定文件的功能

    输入字符串和输出文件的路径,返回一个布尔值用于表示输出是否成功

 

  public static void showFile(String NameMatch,String FilePath){       //实现带*文件的匹配和遍历文件夹的功能

    输出需匹配的文件部分名称和相应路径,函数中会将符合条件的文件名称添加到全局变量Name动态数组中,路径添加到全集变量Path动态数组中

 

  public static void main(String args[])   //主函数,用于对指令进行判断后调用函数执行相应功能

 

  (补充)

  main函数流程图如下:

  

  

三.关键部分代码

  实现读取空行,代码行,和注释行功能代码

  

    public static int[] a(String FilePath){          //实现读取空行,代码行,和注释行的功能。
        int result = 1;
        int code = 0,emp = 0,note = 0;
        boolean empline = true;                 //空行为true
        boolean codeline = false;               //代码行为true
        boolean starnote = false;                //星号注释的判断,注释行为true
        boolean starend = false;                //用于注释尾部判断
        boolean starstart = false;                //用于注释头部判断
        boolean dounote = false;                //双斜杠类型注释判断
        
        
        File f = new File(FilePath);
        DataInputStream dis = null;
        if(!f.isFile() && f.exists()){
            int[] a = {code,emp,note}; 
            return a;
        }
        try {
            /*创建二进制输入流*/
            dis = new DataInputStream(new FileInputStream(f));
            
            /*循环读取并输出信息*/
            int temp = 0;
            while((temp = dis.read())!=-1){
                if(temp == '\n'){
                    if(empline == true)
                        emp++;
                    else if(codeline == true)
                        code++;
                    else
                        note++;
                    empline = true;
                    codeline = false;
                    dounote = false;
                }
                else if(temp ==  ' ' || temp == '\t' || temp == '\r' || temp == '{')
                    ;
                else if(codeline == false){
                    empline =false;
                    if(starnote == true){
                        if(temp == '*')           //为*将标志starend置位true
                            starend = true;
                        else if(temp == '/' && starend == true){  //上一次为*,且这一次为/,则将starnote置位false
                            starnote = false;
                            starend = false;
                        }
                        else 
                            starend = false;
                    }
                    else if(temp == '/'){
                        if(starstart == true)      //两次//且前面没有有效字符表示当前行注释
                            dounote = true;
                        else
                            starstart = true;
                    }
                    else if(temp == '*'){
                        if(starstart == true)     //上次为/ 这次为*,表示注释开始
                            starnote = true;
                        else
                            codeline = true;        //否则为代码行
                    }
                    else if(temp == '}')
                        ;
                    else if(dounote == false)
                        codeline = true;
                }
            }
            if(empline == true)
                emp++;
            else if(codeline == true)
                code++;
            else
                note++;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally{
            if (dis!=null) {
                try {
                    dis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        int[] a = {code,emp,note}; 
        return a;
    }

 

  除去停用词统计字数函数代码

    public static int e(String FilePath,String StopFile){      //实现读取除停用词以外单词的个数的功能
        int result = 0;
        
        String a = "";
        
        String[] stopword = new String[10];
        for(int m = 0;m < 10;m++){
            stopword[m] = "";
        }
        
        
        File f = new File(FilePath);
        File Stop = new File(StopFile);
        DataInputStream dis_1 = null;
        DataInputStream dis_2 = null;
        if(!f.isFile() && f.exists())
            return -1;
        if(!Stop.isFile() && Stop.exists())
            return -1;
        try {
            /*创建二进制输入流*/
            dis_1 = new DataInputStream(new FileInputStream(f));
            dis_2 = new DataInputStream(new FileInputStream(Stop));
            /*循环读取并输出信息*/
            int S = 0,i = 0;
            while((S = dis_2.read())!=-1){
                if(S != ' ')
                    stopword[i] = stopword[i] + (char)S;
                else
                    i++;
            }
            
            int temp = 0,j = 0;
            while(temp != -1 ){                          //第一个循环跳过空格 换行 逗号等  第二个循环跳过正常字符
                while((temp = dis_1.read())!=-1 && (temp == '\n' || temp == '\t' || temp == ' ' || temp == ',' || temp == '\r'))
                    a = "";
                if(temp == -1)                            //当最后一次以空格结尾时,-1表示不计算本次
                    result--;
                else
                    a = a + (char)temp;                    //每当经过一次两个循环时,意味着单词数+1
                while((temp = dis_1.read())!=-1 && temp != '\n' && temp != '\t' && temp != ' ' && temp != ',' && temp != '\r')
                    a = a + (char)temp;
                result++;
                for(j = 0;j <= i;j++){
                    if(stopword[j].equals(a)){
                        result--;
                        break;
                    }
                }
                
            }
            
            
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally{
            if (dis_1!=null) {
                try {
                    dis_1.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (dis_2!=null) {
                try {
                    dis_2.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return result;
    }

  

  实现遍历文件夹,匹配文件功能的函数代码

    public static void showFile(String NameMatch,String FilePath){       //实现带*文件的匹配和遍历文件夹的功能
        File f = new File(FilePath);
        if(f.isFile()){
            if(f.getName().contains(NameMatch)){           //对匹配的文件将其信息添加到动态数组中
                Path.add(FilePath);
                Name.add(f.getName());
            }
        }
        if(f.isDirectory()){
            File[] array = f.listFiles();
            for(int i=0;i<array.length;i++){
                showFile(NameMatch,array[i].getPath());    //递归调用,对该文件夹下的每个项目再次执行此函数。
                //System.out.println(array[i].getName());
            }
        }
    }

 

  主函数中命令判断部分代码

        boolean[] flag = new boolean[7];           //作为命令判断标志,如果存在命令,则将相应位置位为true
        for(i = 0;i < 7;i++)
            flag[i] = false;
        for(i = 0;i < length;i++){
            if(args[i].equals("-c"))
                flag[0] = true;
            else if(args[i].equals("-w"))
                flag[1] = true;
            else if(args[i].equals("-l"))
                flag[2] = true;
            else if(args[i].equals("-a"))
                flag[3] = true;
            else if(args[i].equals("-s"))
                flag[4] = true;
            else if(args[i].equals("-e")){
                flag[5] = true;
                i++;
                stopFile = args[i];             //停用词命令后是停用词文件路径
            }
            else if(args[i].equals("-o")){
                flag[6] = true;
                i++;
                outputFile = args[i];          //输出命令后是输出目的文件
            }

四.测试用例设计过程

  本次共要求设计10个以上测试用例

  我在设计测试用例时首先对每一项功能单独地进行测试,然后组合测试,具体测试用例与测试情况如下:

  1.单独对字符统计进行测试

    -c input1.txt

  2.对输出到文件的功能进行测试

    -c input1.txt -o output.txt

  3.对单词统计进行测试

    -w input2.txt -o output.txt

  4.同时对字符和单词统计功能进行测试

    -w -c input3.txt -o output.txt

  5.对行数统计进行测试  

    -l input4.txt -o output.txt

  6.对文件中空行,代码行,注释行统计功能进行测试

    -a input5.txt -o output.txt

  7.对文件中除去停用词的单词数进行统计

    -w input6.txt -e stopword.txt -o output.txt

  8.对文件夹下符合要求的文件统计单词数

    -w -s *.txt -o output.txt

  9.遍历文件夹下符合要求的文件统计空行 注释行 代码行

    -a -s *5.txt -o output.txt

  10.遍历文件夹下符合要求的文件,统计多种数据

    -a -c -l -s *5.txt -o output.txt

  总之,测试用例所秉承的思想是,先进行单元测试,即对不同功能单元进行测试,然后综合测试,检测代码整体是否能够正确运行。

 

  (补充)

  测试程序设计思路

  在测试代码设计部分,我的思路是调用exe文件执行测试用例,将输出结果记录下来,然后与正确结果进行比对,如果相同,输出测试成功指令,如果不同,则提示错误,如果不能执行而导致无输出,则提示测试用例出现问题。依此法循环执行十个用例,根据最后输出来得出测试结果。

 

五.参考资料

  有关于GitHub的使用参考了廖雪峰的官方网站 :https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/

  有关于转化为exe文件参考了博文:https://www.cnblogs.com/YiYeZhiQiu92/p/7277046.html

  有关于Java I/O流的使用,参考了博文:https://www.cnblogs.com/tengqiuyu/p/6849097.html

 

六.个人感想与小结

  这次作业我花了很多时间,总结原因还是自己的动手能力太差,以后要多加练习,提高自己的专业能力。

  再者,在个人收货方面,通过这次作业,我的Java水平有了一些提高,了解了有关于Java I/O流的操作和对main函数args传参的处理的知识。同时对测试有了初步的接触和了解,测试在软件开发中是一个很重要的环节,自己在这个部分还要多多学习,努力提升自己。

posted @ 2018-03-20 23:21  Cpf_zzZ~  阅读(207)  评论(6编辑  收藏  举报