本项目Github地址:https://github.com/RevRocLin/wc
项目相关要求
基本功能:(已实现)
-c 统计文件字符数
-w 统计文件词的数目
-l 统计文件行数
扩展功能:(已实现)
-s 递归处理目录下符合条件的文件
-a 返回更复杂的数据(代码行 / 空行 / 注释行)
高级功能:(未实现)
-x 显示图形界面
设计实现过程
该项目由三个类实现:
Wc.java:程序主类,实现对输入命令的分割和识别、对目标文件的处理、输出数据
wcFunction.java:功能实现类,实现5个方法:
getCharNumber():将空格符、换行符等无显示字符去除后按行统计字符数
getWordNumber():用StringBuilder.append()方法将读取的每行数据以字符串的形式插入,用空格替换所有非词字符,按空格将字符串拆分后放入字符串数组中,数组长度就是每行的字词数
getLineNumber():用readLine()方法每读一行行数加一
extra_Function1():构造空行和注释行的正则表达式适配器,用Matcher类的find()方法匹配正则表达式适配器,每行匹配到的对应类型的行行数加一
scanFile:调用文件过滤器对目标文件/目录进行递归处理
fileFilter.java:用FileFilter接口的accept()方法对目录下的文件进行筛选
遇到的困难及解决方法
构造匹配注释行的正则表达式出错:查询书上关于正则表达式的内容结合网友发布的有关正则表达式修改自己的表达式
代码说明
处理命令:
public static void main(String[] args) throws IOException { // TODO code application logic here wcFunction function=new wcFunction(); System.out.println("-c 返回文件 file.c 的字符数\n" +"-w 返回文件 file.c 的词的数目 \n" +"-l 返回文件 file.c 的行数"); System.out.println("-s 递归处理目录下符合条件的文件。\n" +"-a 返回更复杂的数据(代码行 / 空行 / 注释行)。"); System.out.println("请输入命令:(格式为:命令 文件路径)"); while(true){ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String input=br.readLine(); String[] commond=input.split(" "); switch(commond[0]) { case "-c": int num1=function.getCharNumber(commond[1]); System.out.println("字符数:"+num1); break; case "-w": int num2=function.getWordNumber(commond[1]); System.out.println("单词数:"+num2); break; case "-l": int num3=function.getLineNumber(commond[1]); System.out.println("行数:"+num3); break; case "-a": int[] num4=function.extra_Function1(commond[1]); System.out.println("空行:"+num4[0]+" "+"代码行:"+num4[1]+" "+"注释行:"+num4[2]); break; case"-s": function.scanFile(new File(commond[1])); break; default: System.out.println("命令不正确"); break; } } }
-c的实现方法:
int getCharNumber(String fileName) throws IOException { int count=0; File file=new File(fileName); String line=null; if(file.exists()){ BufferedReader br=new BufferedReader(new FileReader(file)); while ((line = br.readLine()) != null){ Pattern p = Pattern.compile("\\s*|\t|\r|\n"); Matcher m = p.matcher(line); line = m.replaceAll(""); count += line.length();//按行统计字符 } } else{ System.out.println("文件不存在,请重新输入:"); } return count; }
-w 的实现方法:
int getWordNumber(String fileName) throws IOException{ int count=0; File file=new File(fileName); String[] word=null; if(file.exists()){ BufferedReader br=new BufferedReader(new FileReader(file)); String line=null; StringBuilder sbr=new StringBuilder(); while((line=br.readLine())!=null){ sbr.append(line); String string=sbr.toString(); string=string.replaceAll("\\W", " ");//用空格替换非词字符 word=string.split("\\s+");//按空格将字符串拆分后放入字符串数组中 count=word.length;//数组的长度就是词的数目 } br.close(); } else{ System.out.println("文件不存在,请重新输入:"); } return count; }
-l 的实现方法:
int getLineNumber(String fileName) throws IOException{ int count=0; File file=new File(fileName); if(file.exists()){ BufferedReader br=new BufferedReader(new FileReader(file)); while(br.readLine()!=null){ count++; } } else{ System.out.println("文件不存在,请重新输入:"); } return count; }
-a 的实现方法:
int[] extra_Function1(String fileName) throws IOException{ int null_Line=0; int code_Line=0; int comment_Line=0; int line=0; String str=null; File file=new File(fileName); if(file.exists()){ BufferedReader br=new BufferedReader(new FileReader(file)); Pattern null_Pattern=Pattern.compile("(^\\s*$)|(^\\S$)");// 构造空行的模式匹配(既行的开头和结尾间只有空白字符\s) Pattern comment=Pattern.compile("((//)|(/\\*+)|((^\\s)*\\*)|((^\\s)*\\*+/))+",Pattern.MULTILINE + Pattern.DOTALL);//注释 while((str=br.readLine())!=null){ line++; if(null_Pattern.matcher(str).find()){ null_Line++; } else if(comment.matcher(str).find()){ comment_Line++; } } code_Line=line-comment_Line-null_Line; } else{ System.out.println("文件不存在,请重新输入:"); } int[] count={null_Line,code_Line,comment_Line}; return count; }
文件过滤器:
/** * * @author jakylin */ public class fileFilter implements FileFilter{ @Override public boolean accept(File pathname) { String name=pathname.getName(); if(name.endsWith(".txt")||name.endsWith(".java")||name.endsWith(".c")||name.endsWith(".cpp")||pathname.isDirectory()){ return true; }else{return false;} } }
-s 的实现方法:
void scanFile(File file) throws IOException{ if(file.exists()){ if(!file.isDirectory()){ System.out.println("非法目录,请重新输入:"); } else{ File[] files = file.listFiles(new fileFilter()); for (File file1 : files) { if (file1.isDirectory()) { scanFile(file1); } else { String path=file1.getAbsolutePath(); int num1=getCharNumber(path); int num2=getWordNumber(path); int num3=getLineNumber(path); int[] num4=extra_Function1(path); System.out.println(path); System.out.println("字符数:"+num1+"\n单词数:"+num2+"\n行数:"+num3+"\n空行:"+num4[0]+" "+"代码行:"+num4[1]+" "+"注释行:"+num4[2]); } } } } }
测试运行
测试用文本文件:
测试用文件夹:
测试结果:
PSP开发耗时
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
Planning | 计划 | 15 | 20 |
· Estimate | · 估计这个任务需要多少时间 | 15 | 10 |
Development | 开发 | 100 | 120 |
· Analysis | · 需求分析 (包括学习新技术) | 200 | 250 |
· Design Spec | · 生成设计文档 | 30 | 20 |
· Design Review | · 设计复审 (和同事审核设计文档) | 30 | 30 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 30 | 30 |
· Design | · 具体设计 | 30 | 40 |
· Coding | · 具体编码 | 200 | 220 |
· Code Review | · 代码复审 | 30 | 30 |
· Test | · 测试(自我测试,修改代码,提交修改) | 60 | 80 |
Reporting | 报告 | 60 | 60 |
· Test Report | · 测试报告 | 50 | 60 |
· Size Measurement | · 计算工作量 | 20 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | 20 |
合计 | 890 | 1100 |
项目小结
我在学习新技术和具体编码上花的时间可以看出在实践和知识上都很欠缺。项目过程中对项目的单元测试一窍不通,代码也不敢严谨,不足的地方有很多。整个项目最大的收获是学习到如何系统的完成一个项目和对一个项目的管理。