一、 github项目地址:
二、 Psp表格:
三、 解题思路:
拿到题目的时候,觉得这个作业和之前的编译原理课设很像,但是思考过后,发现编译原理可以运用工具,而此题由于其他功能所以会很麻烦,相似点似乎有些行不通。 而后看了需求,很多需求的描述都不清楚,于是就自己揣摩并和同学们讨论这个需求,当清楚了需求之后就会自然的考虑,哪个模块该怎么编写。确定了这些因素之后就要开始查阅资料,实不相瞒,网上并没有此类代码,因此开发时是摸索着前进,能借助的只有百度等等。而后编写当然是从底层开始,由基本功能开始往上一层一层的添加功能。 编写文件时所查阅的资料并不太多,而且功能编写时所耗费的时间挺多,但是由于奇奇怪怪的测试,就会试出该功能小小的漏洞,而这个debug的耗时却是比正常编写还要多的多。 在编写完基础功能之后,准备提交的时候,才发现之前并没有用过java生成exe,过程真是繁琐,用这个一定要生成exe,简直是反人类的操作。因此就在这会查找很多相关资料,主要链接在第七部分参考链接。四、 程序设计实现过程
代码目前分为一个大类WC,类里包括四个函数和若干变量。 函数分为:1.对参数进行分析的主函数; 2.对停用词表进行输入分析储存的函数; 3.有停用词表的源文件输入分析函数; 4.没有停用词表的源文件输入分析函数。 (由于加了停用词表,对单词数分析的操作会变的很多,因此将有无停用词表的分析操作分开,会减少无停用词表的开销) 函数关系:设置参数,运行程序之后,参数会传递到主函数的args[]参数的数组里。而主函数开始就会对参数数组进行分析,确定那些功能需要,哪些功能不需要,并且传递文件名信息;如果参数有-e .c(即有停用词表)时,调用函数2、3;如果参数没有-e .c(即没有停用词表)时,调用函数4;返回主函数之后,根据参数所选功能,将数据写入输出文件。总体结构如图:
![1341770-20180320204514778-622935985.png](https://images2018.cnblogs.com/blog/1341770/201803/1341770-20180320204514778-622935985.png)
五、 代码说明
for(int i=0;i<args.length;i++)
{ //对输入的指令进行分析 if(args[i].equals("-c")) c=true;else if(args[i].equals("-w")) w=true; else if(args[i].equals("-l")) l=true; else if(args[i].equals("-a")) a=true; else if(args[i].equals("-s")) allfile=true; else if(args[i].equals("-e")) {e=true; stsr=stsr+args[++i];} else if(args[i].equals("-o")) osr=args[++i]; else if(args[i].charAt(0)!='-') ssr=args[i];
}
这段代码是在main函数初始化后的判定,判断哪些功能需要哪些功能不需要,如指令中有-s则调用递归读取所有指定文件,若没有则读取单个文件。由于这样的功能区分,会调用不同程度的函数,大大优化了程序的效率。public static void wordcountwithstoplist(InputStream f) throws IOException {
int cc=0; char c =' '; String temp=""; int wdflag=0; //是否可以算作单词 int wddflag=1; //是否不在停用词表里 int zsflag=0; //是否为单行双杠的注释 int aloneflag=0; //当前行的有效字符数(不算注释和回车空格等) int zflag=0; //是否在//之间的注释 int zzflag=0; //是否在/之后读到了/ int xingflag=0; //是否此是/的星 while ((cc = f.read()) != -1) { xingflag=0; c=(char)cc; ++chars; if (c == '\n') { ++lines; if(aloneflag<=1&&zsflag==0&&zflag==0) ++blackl; //没有或有一个有效字符的行是空行 else if((zsflag==1||zflag==1)&&aloneflag<=2) ++zhushil; //有效字符为0或1个的单行注释或者在//里的行为注释行 else ++codel; //有效字符大于等于两个 if(zzflag==1) {zflag=0; zzflag=0;} zsflag=0; aloneflag=0; wdflag=1; if(!stop.contains(temp)&&!temp.equals("")) wddflag=1; temp=""; }//判断当前词是否在停用词表里 if(c==' '||c==',') {wdflag=1; if(c==' ') zsflag=0; if(!stop.contains(temp)&&!temp.equals("")) wddflag=1;temp="";} if(c!=' '&&c!='\t'&&c!='\r'&&c!='\n') { if(c!=',') { temp=temp+c; if(wdflag==1) { if(wddflag==1) {++words; wddflag=0;wdflag=0;} } } if(zsflag==0&&(zflag==0||zzflag==1)) ++aloneflag; } if(c=='/'&&zflag==0) { if((cc = f.read()) != -1) { c=(char)cc; if(c=='/'&&aloneflag<=2) zsflag=1; //双杠注释开始 if(c=='*') {zflag=1;xingflag=1;} ///**/注释开始 } } if(c=='*'&&zflag==1&&xingflag==0) if((cc = f.read()) != -1) { c=(char)cc; if(c=='/') zzflag=1; ///**/注释结束,在此行结束判定 } } //最后一个词在循环内可能不会分析,因此出来判定其是否分析过 if(!temp.equals("")&&!stop.contains(temp)) ++words; if(aloneflag<=1&&zsflag==0&&zflag==0) ++blackl; else if((zsflag==1||zflag==1)&&aloneflag<=2) ++zhushil; else ++codel; chars=chars-lines+1; } 本段代码为带停用词表的各个数的分析,各个标志所表示的状态如注释所述。如果单词结尾后有多个空格或逗号则跳过,算一个单词。每行字符换行有\r\n两个,因此实际算一个,所以相减,第一行字符没有,所以加一。行数开始为一,遇到换行加一,而注释空行等则根据标志和有效字符的个数判定。private static void getAllFile(ArrayListsourcepathArray, ArrayList sourcenameArray, String rootPath, String keyword) //获取所有文件("*.c") { File rootFile = new File(rootPath); File[] files = rootFile.listFiles(); if (files != null) { for (File f : files) { if (f.isDirectory()) //判断是文件夹 getAllFile(sourcepathArray,sourcenameArray, f.getPath(), keyword); else if (f.getName().indexOf(keyword) == f.getName().length() - keyword.length()) { sourcepathArray.add(f.getPath()); sourcenameArray.add(f.getName()); } }
}
} 本段代码写了递归读取指定文件,匹配名称中的后缀是否一致,并将路径和名称都存进数组里,在读写文件时调用。六、 测试设计过程
本次测试采用白盒测试方法。 测试共有10组,都是针对于功能所进行的,对主要测试功能部分达到语句覆盖,对其他部分达到条件覆盖。 主要功能测试分类:字符数2组 单词数1组 单词数-停用词3组 代码行/空行/注释行4组(最后两组为注释的极端情况) 设计详细用例内容见github。七、 参考文献链接