第二周个人作业WordCount
第二周个人作业WordCount
Github地址:
https://github.com/zhao-123456/WC
PSP2.1表格
PSP2.1 | PSP 阶段 | 预估耗时 (分钟) | 实际耗时 (分钟) |
---|---|---|---|
Planning | 计划 | 20 | 20 |
· Estimate | · 估计这个任务需要多少时间 | 20 | 20 |
Development | 开发 | 200 | 200 |
· Analysis | · 需求分析 (包括学习新技术) | 20 | 20 |
· Design Spec | · 生成设计文档 | 0 | 0 |
· Design Review | · 设计复审 (和同事审核设计文档) | 0 | 0 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 | 10 |
· Design | · 具体设计 | 30 | 30 |
· Coding | · 具体编码 | 500 | 500 |
· Code Review | · 代码复审 | 10 | 10 |
· Test | · 测试(自我测试,修改代码,提交修改) | 30 | 35 |
Reporting | 报告 | 30 | 30 |
· Test Report | · 测试报告 | 15 | 15 |
· Size Measurement | · 计算工作量 | 5 | 5 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | 20 |
合计 |
910 | 915 |
解题思路
拿到题目后,老师推荐语言是java,所以我又去重新学习了一遍。分析一下题目,基本功能是要实现对指定文件的字符数,单词数,行数的统计以及将输出结果放入指定文件中。我第一反应是对文件一行一行进行读入,进而统计字符数,单词数,行数。而对于扩展功能,递归处理目录下符合条件的文件,则可从输入中获取文件名的后缀,再遍历该路径下所有文件找到符合后缀的文件名,进行操作。返回更复杂的数据(代码行 / 空行 / 注释行)则可使用正则表达式。对于停用词表的想法就是先获取表中单词,将其放入列表中,在进行逐行读取单词时判断其是否在该列表中,若不在,单词数加一。至于对高级功能,因为时间有限,尚未考虑。
程序设计实现过程
由wordcount.java和main.java两个java文件构成 。
wordcount.java主要实现统计的方法,包含count()函数,根据输入参数来获取flag的值进而选择不同的方法。basiccount()函数用来统计文件基本的字符数,单词数,行数。complexcount()函数则是通过正则式来判断代码行 / 空行 / 注释行并进行统计。
而main.java主要实现对文件的读取,获取参数,对停用词表的操作。包含getparameters()函数,它完成对输入参数的获取识别,并进行合理划分。ListFile(),Liststop()则完成对文件的存放和对停用词表中单词的存放。
代码说明
wordcount.java中的count函数可以属于控制函数,根据参数来获取flag的值进而选择不同的方法。
1 public void count(Vector<String> parameters)throws IOException{ 2 for(int i=0;i<source.size();i++){ 3 if(parameters.contains("-c")){ 4 flag=1; //对每种参数进行标记 5 basiccount(source.get(i)); 6 } 7 if(parameters.contains("-w")){ 8 flag=2; 9 basiccount(source.get(i)); 10 } 11 if(parameters.contains("-l")){ 12 flag=3; 13 basiccount(source.get(i)); 14 } 15 if(parameters.contains("-a")){ 16 complexcount(source.get(i)); 17 } 18 } 19 }
basiccount()函数使用统计字符数,单词数,行数。
1 public static void basiccount(File name)throws IOException{ 2 int charnum=0; 3 int wordnum=0; 4 int linenum=0; 5 try{ 6 InputStreamReader reader=new InputStreamReader(new FileInputStream(name)) ; 7 BufferedReader br=new BufferedReader(reader); 8 while(br.read()!=-1){ 9 String s=br.readLine(); //按行读取 10 charnum=s.length()+charnum+1; 11 String list[]=s.split(" |,"); 12 //wordnum+=list.length; 13 for(int i=0;i<list.length;i++){ 14 if(lists.isEmpty()){ 15 if(!Pattern.matches("\\s*",list[i])){ //停用词表为空 16 wordnum++; 17 } 18 } 19 20 else { 21 if(!lists.contains(list[i])&&!Pattern.matches("\\s*",list[i])){ //停用词表不为空 22 wordnum++; 23 } 24 } 25 26 } 27 linenum++; 28 } 29 reader.close(); 30 }catch (Exception e){ 31 e.printStackTrace(); 32 } 33 switch(flag){ 34 case 1: 35 String result=name.getName()+",字符数:"+charnum+"\r\n"; 36 output.write(result.getBytes()); 37 System.out.println(result); 38 break; 39 case 2: 40 String result1=name.getName()+",单词数:"+wordnum+"\r\n"; 41 output.write(result1.getBytes()); 42 System.out.println(result1); 43 break; 44 case 3: 45 String result2=name.getName()+",行数:"+linenum+"\r\n"; 46 output.write(result2.getBytes()); 47 System.out.println(result2); 48 break; 49 } 50 } 51 }
complexcount()函数则是通过正则式来判断代码行 / 空行 / 注释行。
1 public static void complexcount(File name)throws IOException{ 2 int codeline=0; 3 int nullline=0; 4 int annotationline=0; 5 try{ 6 InputStreamReader reader=new InputStreamReader(new FileInputStream(name)) ; 7 BufferedReader br=new BufferedReader(reader); 8 boolean comment = false; 9 Pattern annotationLinePattern = Pattern.compile("((//)|(/\\*+)|((^\\s)*\\*)|((^\\s)*\\*+/))+", 10 Pattern.MULTILINE + Pattern.DOTALL); // 注释匹配器(匹配单行、多行、文档注释) 11 Pattern nullLinePattern = Pattern.compile("^\\s*$"); // 空白行匹配器(匹配回车、tab键、空格) 12 13 Pattern codeLinePattern = Pattern.compile("(?!import|package).+;\\s*(((//)|(/\\*+)).*)*", 14 Pattern.MULTILINE + Pattern.DOTALL);// 代码行匹配器(以分号结束为一行有效语句,但不包括import和package语句) 15 16 while(br.read()!=-1){ 17 String s=br.readLine(); 18 if(annotationLinePattern.matcher(s).find()){ 19 annotationline++; 20 } 21 if(nullLinePattern.matcher(s).find()){ 22 nullline++; 23 } 24 if(codeLinePattern.matcher(s).find()){ 25 codeline++; 26 } 27 } 28 reader.close(); 29 }catch (Exception e){ 30 e.printStackTrace(); 31 } 32 String result=name.getName()+",代码行/空行/注释行:"+codeline+"/"+nullline+"/"+annotationline+"\r\n"; 33 output.write(result.getBytes()); 34 System.out.println(result); 35 }
对于main.java,十分关键的是getparameters()函数,它完成对输入参数的获取识别,是指实现对应的功能。
1 public static void getparameters(String[] args){ 2 outpath="result.txt"; 3 parameters=new Vector<String>(); 4 source=new Vector<File>(); //初始化,避免空指针错误 5 lists=new Vector<String>(); 6 for(int i=0;i<args.length;i++){ 7 if(args[i].equals("-o")){ //判断“-o”后面是否跟有文件名 8 if(i<args.length-1){ 9 outpath=args[i+1]; 10 } 11 else{ 12 System.out.println("wrong"); 13 } 14 15 } 16 else if(args[i].equals("-c")||args[i].equals("-w")||args[i].equals("-l")||args[i].equals("-a")){ 17 parameters.addElement(args[i]); //将参数加入parameters容器中 18 } 19 else if(args[i].equals("-s")){ 20 for(int j=0;j<args.length;j++){ 21 if(args[j].contains("*")){ 22 String type=args[j].substring(args[j].indexOf("."));//获取文件的类型 23 ListFile(type); 24 } 25 } 26 } 27 else if(args[i].equals("-e")){ 28 stopname=args[i+1]; 29 try{ 30 Liststop(stopname); 31 } 32 catch(Exception e){ 33 e.printStackTrace(); 34 } 35 } 36 else{ 37 source.addElement(new File(args[i])); 38 } 39 } 40 }
最后的ListFile(),Liststop()则完成对文件的存放和对停用词表中单词的存放。
1 public static void Liststop(String stopname)throws IOException{ 2 File file=new File(stopname); 3 InputStreamReader reader=new InputStreamReader(new FileInputStream(file)); 4 BufferedReader br=new BufferedReader(reader); 5 while(br.read()!=-1){ 6 String s=br.readLine(); 7 String liststop[]=s.split(" "); 8 for(int i=0;i<liststop.length;i++){ 9 lists.addElement(liststop[i]); 10 } 11 } 12 reader.close(); 13 } 14 15 public static void ListFile(String type){ 16 File file=new File(nowpath); 17 File[] files=file.listFiles(); //将当前路径下所有文件装入文件列表中 18 if(files==null){ 19 System.out.println("null"); 20 } 21 for(int i=0;i<files.length;i++){ 22 if(files[i].isFile()&&files[i].getName().endsWith(type)){//判断是否以特定类型结尾的文件 23 source.addElement(files[i]); 24 } 25 else if (files[i].isDirectory()) { 26 ListFile(type);//递归 27 } 28 } 29 } 30 }
测试设计过程
这里都是通过控制台进行的测试
file1.c
1 !@#$%^&*()_+{}|"?><[]\;',./~`a
file2.c
import java.util.Vector; public class wordcount { public static Vector<File> source; public static int flag; private File outfile; public static String outpath; private static OutputStream output; /*ds 对方是否是 sfs*/ public wordcount(Vector<File> source,String outpath)throws IOException{ this.source=source; this.outpath=outpath; this.outfile=new File(outpath); this.output=new FileOutputStream(outfile); }
file3.c
1 File write,name = new File(outputPath); 2 writename.createNe|wFile(); 3 Buffe,redWriter out = new BufferedWrit,er(new FileWriter(writename)); 4 out.close();
wc.exe -c -w -l *.c -o out.txt
wc.exe -s -a *.c
wc.exe -s -a –c -w *.c –e stop.txt –o output.txt
out.txt
file1.c,字符数:30 file1.c,单词数:2 file1.c,行数:1 file2.c,字符数:466 file2.c,单词数:41 file2.c,行数:18 file3.c,字符数:184 file3.c,单词数:16 file3.c,行数:4
参考链接