WordCount作业

GitHub 项目地址

https://github.com/cosensible/WordCount

PSP表格

PSP2.1 PSP阶段 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 15 30
Estimate 估计这个任务需要多少时间 10 10
Development 开发 30 30
Analysis 需求分析(包括学习新技术) 20 50
Design Spec 生成设计文档 0 0
Design Review 设计复审 0 0
Coding Standard 代码规范(为目前的开发制定合适的规范) 10 10
Design 具体设计 30 30
Coding 具体编码 600 1200
Code Review 代码复审 30 30
Test 测试 120 120
Reporting 报告 60 90
Size Measurement 计算工作量 5 10
Postmortem & Process Improvement Plan 事后总结,并提出过程改进计划 20 20
  合计 950 1630

解题思路

拿到题目以后觉得基本功能实现起来挺简单的,扩展功能中觉得停用词表这个功能挺简单,只要将文件中的停用词读出来后放到一个ArrayList中即可,方便以后使用。递归读取文件一开始觉得有些乱,不知如何下手,在网上查了查,发现实现起来也挺简单的,具体参考这里。然而,对于 “代码行/空行/注释行” 的统计,我觉得这里的情况实在太多了,尤其是对注释行的判定,不过,仔细读了要求后算是大概知道规则了,不知道自己有没有理解错。最后,没时间和精力去完成高级功能了,因为自己身体这两天都快被掏空了。之后就开始编码了,因为自己这学期稍微看了一点Java,所以还算比较熟悉。但是,对于测试的编写,自己很迷惑,不知道如何去编写,想了一会儿,还是决定先把代码写完,实现功能再说。
还有一个要求是要生成exe文件,这个第一想法便是Google一下,于是便有了这个链接

程序设计实现过程

由于功能看起来还算比较少,所以自己就没有详细思考如何组织代码,只是想着每个功能对应一个函数,先把基本功能做完再说。做完基本功能后,觉得代码量就有些多了,于是在扩展功能开始前,自己分析了一下应该如何组织这些功能对应的函数。基本想法是在主函数中对扩展功能的参数进行分析,因为他们基本都涉及到对文件的读写操作,然后将基本功能(-c -w -l -a)封装在一个函数中,方便递归分析功能(-s)的实现。由于输出结果要按照规定的顺序输出到文件中,所以在基本功能封装函数中用了一个TreeMap,它对里面的键值对可以按键大小自动排序,所以在读取信息时,可以按照规定的顺序输出。

代码说明

返回字符数

主要使用FileReaderread()函数

while((fileReader.read())!=-1)
    ++num;

返回文件行数

主要使用FileReaderreadLine()函数

while(fileReader.readLine()!=null)
    ++num;

返回单词数

主要用到String的split()函数对字符分割。首先跳过空行,然后将每行中的字符串按空字符(多个空格、制表符等等)分割后再按逗号分割。去掉空字符串后对单词进行统计,统计时要用到装有停用词的ArrayList。

while ((str = fileReader.readLine()) != null) {
    if (!str.equals("")) {//跳过空行
        for (String s : str.split("\\s+")) {//将一行以多个空字符分割
            for (String word : s.split(",")) {//以逗号分割
                if (!stopLists.contains(word)&&!word.equals(""))//stopList不含单词且不为空
                    num++;
            }
        }
    }
}

返回 “代码行/空行/注释行” 数量

对 “代码行/空行/注释行” 的判断标准如下:

  • 代码行:本行包括多于一个字符的代码。
  • 空行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如{
  • 注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:}//注释,在这种情况下,这一行属于注释行。
int[] lineTypes=new int[3];//分别为代码行,空行,注释行
while((str=fileReader.readLine())!=null){
    str=str.replaceAll("\\s+","");
    //行内无字符或者有一个字符且为'{'或'}'时,为空行
    if (str.equals("")||str.length()==1&&(str.equals("{")||str.equals("}")))
        lineTypes[1]++;
    else if (str.contains("/*")){
        //以/*开头,且位于行首或者前面有一个字符且为'{'或'}'时,为注释行
        if (str.indexOf("/*")==0||str.indexOf("/*")==1&&(str.charAt(0)=='{'||str.charAt(0)=='}')){
            lineTypes[2]++;
            if (str.contains("*/"))// 注释结束符*/在本行
                continue;
            while((str=fileReader.readLine())!=null){//注释结束符不在同一行
                if (str.contains("*/")){
                    if (str.indexOf("*/")==(str.length()-2)) //注释结束符在当前行末尾,是注释行
                        lineTypes[2]++;
                    else
                        lineTypes[0]++;//不在末尾,代码行
                    break;
                }
                lineTypes[2]++;//没遇到*/结束注释前,行都为注释行
            }
        }
    }
    //以//开头,且位于行首或者前面有一个字符且为'{'或'}'时,为注释行
    else if (str.indexOf("//")==0||str.indexOf("//")==1&&(str.charAt(0)=='{'||str.charAt(0)=='}'))
        lineTypes[2]++;
    else//其他行为代码行
        lineTypes[0]++;
}

递归读取文件

这里用到File类,它有两个函数:isFile()isDirectory(),分别判断文件对象是文件还是目录。如果是文件,判断它是否符合条件(后缀),符合就加入一个ArrayList文件集。如果是一个目录就进行递归查找。

for(int i=0;i<files.length;i++) {
    if(files[i].isFile()) {//如果是文件
        String tmp=files[i].getName();
        //判断文件名是否符合条件(比如后缀)
        if (tmp.indexOf(".c")==tmp.length()-signal.length())//如果包含signal
            fileList.add(files[i].getCanonicalPath());//添加文件路径
    }
    else if(files[i].isDirectory()) {//如果是文件夹
        if (files[i].getName().equals("jre")) {//跳过程序依赖环境的目录查找
            System.out.println("ignore this catelog named jre.");
            continue;
        }
        //文件夹需要调用递归
        fileList.addAll(getFile(files[i].getPath(),signal));
    }
}

以上便是主要功能实现的函数,详细代码可根据文首给出的项目地址查看。

测试设计

白盒测试介绍

根据软件产品的内部工作过程,在计算机上进行测试,以证实每种内部操作是否符合设计规格要求,所有内部成分是否已经过检查。这种测试方法就是白盒测试。白盒测试把测试对象看做一个打开的盒子,允许测试人员利用程序内部的逻辑结构及有关信息,设计或选择测试用例,对程序所有逻辑路径进行测试。通过在不同点检查程序的状态,确定实际的状态是否与预期的状态一致。这里主要采用基于独立路径的测试方法。

统计字符数或行数

统计字符数和行数类似,加入了停用单词表的参数后,只需要最后一个分支节点加一个判定条件即可,对以下程序图无影响。该程序图有一个分支节点,所以有两条独立路径。


image
路径 输入 预期输出 实际输出
A->B->C NULL 0 0
A->B->B->C 'a' 1 1

统计单词数

共有五个分支节点,故有六条独立路径。


image
路径 输入 预期输出 实际输出
A->B->C->D->E->F->G 空字符 + ,test 1 1
A->B->G NULL 0 0
A->B->C->B->C->D->E->F->G 空行 + 空字符 + ,test 1 1
A->B->C->D->B->C->D->E->F->G 不存在
A->B->C->D->E->D->E->F->G 不存在
A->B->C->D->E->F->D->B->G 空字符行 0 0

统计 “代码行/空行/注释行”

由于代码行/空行/注释行的判定标准很复杂,所碰到的情况也很多,会产生很多判定节点,其程序图如下图所示:


image

这个程序图非常复杂,我尽量画得很简洁了,但是看起来依旧不好看。可以看到,图中有11个判定节点,所以共有12条独立路径,具体的测试过程非常复杂,以下直接给出测试的文本文件:

test()
{
File writename = new File(outputPath);
            writename.createNewFile();
codeLine*/

            BufferedWriter out = new BufferedWriter(new FileWriter(writename));
        //noteLine
            out.write(outputBuffer);

/*noteLine
/*noteLine
*/
/*noteLine*/
/*noteLine
//noteLine
*/codeLine
            out.flush();
            out.close();
}//noteLine
for(){
}/*noteLine*/

预期输出:atest.c,代码行/空行/注释行: 10/3/9
实际输出:atest.c,代码行/空行/注释行: 10/3/9

返回统计结果

这个函数组装几个基本功能(-c -w -l -a 参数),主要用来给递归统计信息功能服务。以下是基本程序图:

image

通过分析知道有5条独立路径。

路径 输入 预期输出 实际输出
A->B->C->G->H 输入命令-c 输出字符统计结果 输出字符统计结果
A->B->D->G->H 输入命令-w 输出单词统计结果 输出单词统计结果
A->B->E->G->H 输入命令-l 输出行数统计结果 输出行数统计结果
A->B->F->G->H 输入命令-a 输出行类型统计结果 输出行类型统计结果
A->B->C->G->B->D->G->H 输入命令-c -w 输出字符和单词统计结果 输出字符和单词统计结果

递归获取满足条件的文件

该函数递归获取当前目录下的所有给定后缀的文件路径,且返回文件路径结果集,这里的分析以.c后缀为例。程序图如下图所示:

image

只有五条独立路径是有效的,如下表所示:

路径 输入 预期输出 实际输出
A->B->G 目录下无文件且无目录 空文件集 空文件集
A->B->C->E->B->G 目录下只有一个文件且后缀为.c 返回一条结果 返回一条结果
A->B->C->B->G 目录下只有一个文件且后缀不是.c 空文件集 空文件集
A->B->D->F->B->G 目录下只有一个jre目录 空文件集 空文件集
A->B->D->B->C->E->B->G 目录下有一个只含有一个.c文件的不为jre的目录 一条结果 一条结果

以上内容就是主要功能的测试设计。

WordCount 使用说明

具体使用说明详见项目地址

引用

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,647评论 18 139
  • 〇、前言 本文共108张图,流量党请慎重! 历时1个半月,我把自己学习Python基础知识的框架详细梳理了一遍。 ...
    Raxxie阅读 18,942评论 17 410
  • 官网 中文版本 好的网站 Content-type: text/htmlBASH Section: User ...
    不排版阅读 4,380评论 0 5
  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,145评论 0 13
  • 李白x王昭君#情人节贺文# 1.“妈妈,今天人好多啊。”一个小姑娘踮着脚尖嘟囔着嘴。“没办法啊,今天过年,只有这一...
    奶味萝莉阅读 10,017评论 7 32