• 第2周个人作业:WordCount


    • Github项目链接:

      https://github.com/JarrySmith/WC


    • PSP表格:

    PSP2.1

    PSP阶段

    预估耗时

    (分钟)

    实际耗时

    (分钟)

    Planning

    计划

     10

     5

    · Estimate

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

     10

     5

    Development

    开发

     825

     1100

    · Analysis

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

     200

     300

    · Design Spec

    · 生成设计文档

     30

     60

    · Design Review

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

     20

     30

    · Coding Standard

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

     15

     20

    · Design

    · 具体设计

     30

     30

    · Coding

    · 具体编码

     400

     450

    · Code Review

    · 代码复审

     30

     60

    · Test

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

     100

     150

    Reporting

    报告

     60

     70

    · Test Report

    · 测试报告

     30

     40

    · Size Measurement

    · 计算工作量

     10

     10

    · Postmortem & Process Improvement Plan

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

     20

     20

     

    合计

     890

     1175


    • 解题思路

              首先很明显,分为包含-s的目录寻找以及非目录寻找的其他命令,我采取的是遍历命令行参数,获取需要进行的操作,如计算单词,计算行数等等.然后有些选项如-o,-e则在第一遍遍历的时候进行检测,其后面是不是有指定文本,如果指定了,那么把输出指向该文本,如果没有指定,那么就直接报错,不需要执行接下来的命令,加快了速度.

         说到文本,那就有关于文本读写方面的内容,我参考了博客【1】中的文本操作。递归遍历参考了博客【2】,获取当前路径参考了博客【3】

       再统计字符,单词,行数比较简单,不多说.值得注意的是-s和-a。-s需要指定特定目录下的指定类型的文本,这里牵涉到关于文本类型的过滤,是默认当前目录还是命令行传入的目录.*.type可以单独存在也可接在目录后面,这都是需要在遍历的时候去解析的。至于-a,自然是关于注释行,空行,代码行的判断了,我的实现是,先判断是不是空行,再判断是不是注释行,如果都不是,那就是代码行.其中有一种是多行注释的最后加上了代码,算是代码行,关于这个,在多行结束判断中,加入一个判断最后一个字符是否为'/'。

             对于每个选项的细节实现上不做过多的展开.稍后的代码展现可以再看到具体的.


    •   程序设计实现过程

        由于工程量不大,所以把所有函数写在一个类里静态调用.共十一个函数.

      countchars、countlines、count_word分别统计字符数,行数,单词数
      is_emptyline、is_expline 用来判断是否为空行,注释行,是被countdetail调用
      get_stopword、readToString、saveresult都是辅助函数,功能为获取停用词表的词,将读入的文本转化为字符串,保存统计结果

    WC、traversepath为两个关键的入口函数,根据是否包含-s分为两个部分去进行统计工作

    
    
    • 代码说明

       1.WC函数,关键入口函数,解析命令行参数表.在第一遍遍历进行了错误判断,利用param是否包含-s进行分支选择,分别处理

    public static void WC(String[] args) {
            int words = 0;
            int lines = 0;
            int chars = 0;
            int[] detail = new int[3];
    
            CharSequence save = ".txt";
            String filepath = null;
    
            boolean checked_file = false;
            for (int i = 0; i < args.length; i++) {
                if (args[i].contains(".txt")) continue;
                //停用词的文件判断
                if (args[i].equals("-e")) {
                    if (i == args.length - 1) {
                        System.out.println("没有指定停用词文本");
                        err = true;
                    } else if (!(args[i + 1].contains(save))) System.out.println("停用词文本需紧跟在-e后");
                    else stop_path = args[i + 1];
                }
                //判断是否函数输出文本
                if (args[i].equals("-o")) {
                    if (i == args.length - 1) {
                        System.out.println("没有指定输出结果文本");
                        err = true;
                    } else if (!(args[i + 1].contains(save))) System.out.println("result.txt需紧跟在-o后");
                    else save_path = args[i + 1];
                }
                string_args.append(args[i]);
            }
            param = string_args.toString();
            if (!err) {
                if (param.contains("-s")) {
                    //默认path为当前目录
                    String path =  System.getProperty("user.dir");
                    for (int i = args.length - 1; i > 0; i--) {
                        if (args[i].contains("*.")) {
                            //获取指定文件类型和指定目录
                            if(args[i].length()>15) path= args[i].split("\.")[0].replace("*","");
                            filetype = "." + args[i].split("\.")[1];
                        }
                    }
                    //开始遍历目录
                    traversepath(path);
                } else {
                    //错误判断
                    for (int i = 0; i < args.length; i++) {
                        if (args[i].contains("*.")){err=true;System.out.println("只有输入-s才能进行全目录遍历规定文件");}
                        if (args[i].contains(".")) {
                            filepath = args[i];
                            break;
                        }
                    }
                if(!err)
                {
                    //及非遍历统计
                if (param.contains("-c")) chars = countchars(filepath);
                if (param.contains("-l")) lines = countlines(filepath);
                if (param.contains("-w")) words = count_word(filepath);
                try {
                    if (param.contains("-a")) detail = countdetail(filepath);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                }
            }
        }
            saveresult(words,lines,chars,detail,filepath);
            }

        2.traversepath函数 根据特定的文本类型,遍历指定目录及其子目录,分别进行统计工作然后保存

    public static void traversepath(String path) {
            File file = new File(path);
            if (file.exists()) {
                File[] files = file.listFiles();
                //如果是个空文件夹
                if (files.length == 0) {
                    return;
                } else {
                    for (File file2 : files) {
                        if (file2.isDirectory()) {
                            //遍历子目录
                            traversepath(file2.getAbsolutePath());
                        } else {
                            String filename = file2.getName();
                            if (filename.endsWith(filetype)) {
                                String filepath = path + '\' + filename;
                                int words = 0;
                                int lines = 0;
                                int chars = 0;
                                int[] detail = new int[3];
                                //根据参数进行统计
                                try {
                                    if (null == param) break;
                                    if (param.contains("-a")) detail = countdetail(filepath);
                                    if (param.contains("-w")) words = count_word(filepath);
                                    if (param.contains("-c")) chars = countchars(filepath);
                                    if (param.contains("-l")) lines = countlines(filepath);
                                    saveresult(words, lines, chars, detail, filename);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                }
            }
        }

    • 测试设计过程

    如何设计?覆盖所有判断路径,分支

      关于命令行参数不完整和不正确 会导致程序高风险

      测试用例设计如下:

    1. wc.exe -l a.c
    2. wc.exe -w a.c
    3. wc.exe -c a.c
    4. wc.exe -a a.c
    5. wc.exe -l a.c -o result.txt
    6. wc.exe -l a.c -o
    7. wc.exe -w a.c -e stoplist.txt
    8. wc.exe -w a.c -e
    9. wc.exe -s -a *.c
    10. wc.exe -s -a
    11. wc.exe -s -a *.java

      测试脚本代码如下:

    wc.exe -l a.c
    wc.exe -w a.c
    wc.exe -c a.c
    wc.exe -a a.c
    wc.exe -l a.c -o result.txt
    wc.exe -l a.c -o
    wc.exe -w a.c -e stoplist.txt
    wc.exe -w a.c -e
    wc.exe -s -a *.c
    wc.exe -s -a
    wc.exe -s -a *.java
    pause>nul


    • 参考文献链接

      【1】https://www.cnblogs.com/oracleblogs/p/6591656.html

      【2】https://www.cnblogs.com/azhqiang/p/4596793.html

      【3】https://www.cnblogs.com/franson-2016/p/5728280.html

     

  • 相关阅读:
    Java核心类库——线程Thread
    xml基本写法和dtd schema的用法,JAVA读写XML
    Java核心类库——文件和文件夹的管理File类
    使用文件依赖项缓存页输出
    根据 HTTP 标头缓存页的版本
    缓存 ASP.NET 页的某些部分
    根据请求浏览器缓存页的版本
    根据自定义字符串缓存页的版本
    缓存页的多个版本
    阿拉的宣告~~~
  • 原文地址:https://www.cnblogs.com/Jarry-smith/p/8597560.html
Copyright © 2020-2023  润新知