github链接:https://github.com/Nancy0611/wc
一:项目相关要求
该项目能统计文本文件的字符数、单词数和行数。这个项目要求写一个命令行程序,模仿已有wc.exe 的功能,并加以扩充,给出某程序设计语言源文件的字符数、单词数和行数。实现一个统计程序,它能正确统计程序文件中的字符数、单词数、行数,以及还具备其他扩展功能,并能够快速地处理多个文件。
程序处理用户需求的模式为:wc [parameter] [file_name]
二:项目功能完成情况
基本功能:
- wc -c <file> 统计文件的字符数(完成)
- wc -w <file> 统计文件词的数目(完成)
- wc -l <file> 统计文件的行数 (完成)
扩展功能:
- wc -s <file> 递归处理目录下符合条件的文件(已完成)
- wc -a <file> 返回更复杂的数据:代码行 / 空行 / 注释行(已完成)
说明:
空行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”。
代码行:本行包括多于一个字符的代码。
注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:} //注释,在这种情况下,这一行属于注释行。
高级功能:
-
wc -x [parameter] 这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、行数等全部统计信息。(未完成)
三:设计思路
-
获取输入命令行参数,利用正则表达式校验输入命令行是否符合格式
-
如果输入命令符合格式要求则利用split(" ")按照空格将命令拆开并存储于数组
-
获取命令数组的最后一个元素,即为待统计的文件名或目录
-
若输入为文件则直接进行统计,若输入为目录则通过递归处理目录下的文件
-
输入参数[-c] [-w] [-l] [-a] 初始值设为false,一旦输入将值置为true以此选择性地显示
-
根据不同的命令对数据进行相应的处理
-
-
字符数:获取每行的字符数,逐行叠加
- 词的数目:获取每行除去空格的字符数,逐行叠加
-
行数:利用readline()不为 null,逐行叠加
- 空行:利用正则表达式统计只含"{"或 "}"或 " "的行数
-
注释行:统计除去"//"、"{//"、"/*"开头、"*/"结尾、"/* 单行注释 */"、"/*多行注释*/"
- 代码行:总行数除去代码行和空行即可得
-
四:设计思路
五:代码说明
程序入口,获取输入命令行,检验后若符合格式,则将命令解析并调用相关功能函数
1 public static void main(String[] args) throws IOException { 2 3 scan = new Scanner(System.in); 4 String commend=scan.nextLine(); 5 boolean result=checkInput(commend); 6 //输入格式为:wc [parameter] [file_name] 7 8 if(!result){ 9 System.out.println("输入指令不符格式"); 10 }else{ 11 String[] comArray=commend.split(" "); 12 int comLength=comArray.length; 13 String File_name=comArray[comLength-1];//获取文件名 14 ArrayList<File> ff = new ArrayList<File>(); 15 getFromFile_name(File_name); 16 17 for(File perfile:file){ 18 br=new BufferedReader(new FileReader(perfile)); 19 countData(br); 20 } 21 status(comArray,comLength);//修改cwl状态 22 display(c,w,l,a);//显示 23 br.close(); 24 } 25 }
正则表达式检验输入命令行格式
1 public static boolean checkInput(String input){//正则表达式校验输入命令行 2 boolean flag=false; 3 try{ 4 String pattern="^wc\s+(\-[cwlas]\s+){1,5}\s*\S+$"; 5 Pattern regex=Pattern.compile(pattern); 6 Matcher matcher=regex.matcher(input); 7 flag=matcher.matches(); 8 }catch(Exception e){ 9 flag=false; 10 } 11 return flag; 12 }
根据输入文件名或文件路径获取文件
1 public static ArrayList<File> getFromFile_name(String path){ 2 File f=new File(path); 3 file=new ArrayList<File>(); 4 if(f.isFile()&&f.exists()){ 5 file.add(f); 6 }else if(f.isDirectory()){ 7 File[] files=f.listFiles(); 8 for(File fis: files){ 9 if(fis.isFile()){//文件 10 file.add(fis); 11 }else if(fis.isDirectory()){//目录 12 //System.out.println(fis.getAbsolutePath()); 13 getFromFile_name(fis.getAbsolutePath()); 14 } 15 } 16 } 17 return file; 18 }
根据输入命令行的解析结果修改c w l a的状态,输入含有以上字符则标记为true
1 public static void status(String[] comArray,int comLength){//修改cwla状态 2 for(int i=0;i<comLength;i++){ 3 switch(comArray[i]){ 4 case "-c": 5 c=true; 6 break; 7 8 case "-w": 9 w=true; 10 break; 11 12 case "-l": 13 l=true; 14 break; 15 16 case "-a": 17 a=true; 18 break; 19 20 default: 21 break; 22 } 23 } 24 }
根据标记的c w l a的值来选择显示的内容
1 public static void display( boolean c,boolean w,boolean l,boolean a){ 2 //选择显示部分 3 if(c){ 4 System.out.println("字符数:"+countChar); 5 } 6 if(w){ 7 System.out.println("词的数目:"+countWord); 8 } 9 if(l){ 10 System.out.println("行数:"+countLine); 11 } 12 if(a){ 13 System.out.println("代码行:"+codeLine+" 空行:"+blankLine+" 注释行:"+commentLine); 14 } 15 }
计算功能
1 public static void countData(BufferedReader br){//计算部分 2 boolean comment=false; 3 try { 4 while((line=br.readLine())!=null){ 5 /*统计字符数 */ 6 countChar+=line.length(); 7 /*统计词的数目 */ 8 countWord+=line.split(" ").length; 9 /*统计行数 */ 10 countLine++; 11 line=line.trim(); 12 /* 统计空行*/ 13 if(line.matches("[\s&&[^\n]]*$")){ 14 blankLine++; 15 }else if(line.equals("{")||line.equals("}")){ 16 blankLine++; 17 /* 统计注释行 */ 18 }else if(line.startsWith("/*")&&!line.endsWith("*/")){ 19 commentLine++; 20 comment=true; 21 }else if(true==comment){ 22 commentLine++; 23 if(line.endsWith("*/")){ 24 comment=false; 25 } 26 }else if(line.startsWith("//")){ 27 commentLine++; 28 }else if(line.startsWith("/*")&&line.endsWith("*/")){ 29 commentLine++; 30 }else if(line.startsWith("}//")){ 31 commentLine++; 32 /*统计代码行 */ 33 }else{ 34 codeLine++; 35 } 36 } 37 38 } catch (IOException e) { 39 // TODO Auto-generated catch block 40 e.printStackTrace(); 41 } 42 43 }
六:测试截图
- 根据文件名统计(非递归)
输入命令
wc -c -l -w -a E: est est1.txt
文件截图:
测试结果:
- 根据文件路径统计(递归处理)
输入命令:
wc -s -c -l -w -a E: est
文件截图:
E: est est1.txt
E: estseles est2.txt
测试结果:
七:PSP时间统计
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 80 |
· Estimate | · 估计这个任务需要多少时间 | 200 | 300 |
Development | 开发 | 180 | 210 |
· Analysis | · 需求分析 (包括学习新技术) | 20 | 30 |
· Design Spec | · 生成设计文档 | 10 | 15 |
· Design Review | · 设计复审 (和同事审核设计文档) | 10 | 10 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 15 | 15 |
· Design | · 具体设计 | 30 | 45 |
· Coding | · 具体编码 | 160 | 190 |
· Code Review | · 代码复审 | 20 | 20 |
· Test | · 测试(自我测试,修改代码,提交修改) | 20 | 20 |
Reporting | 报告 | 60 | 80 |
· Test Report | · 测试报告 | 10 | 10 |
· Size Measurement | · 计算工作量 | 10 | 10 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | 20 |
合计 | 795 | 1055 |
八:项目总结
关于wordcount,首先,一开始的构思是先读取文件,一段时间没有使用java,对io流的相关内容不是很熟悉,成功将文件存进ArrayList中后我没有考虑到Array List变量之间的赋值问题,直接用=去赋值,发现取出的数据出错,经过上网搜索了解了关于ArrayList对象之间赋值该注意的问题,收获不少。其次,对输入指令格式的验证问题,由于之前没有接触过正则表达式,在正则表达式的相关内容上花费了挺多时间。最后,关于项目编程还是要多实践,本次课程设计一开始都是停留在想的阶段,一直没怎么实践,结果发现过去了挺长时间仍旧没有进度。经过这次课程设计,温习了java的相关内容,同时又发现了许多新的问题,在解决问题的过程受益匪浅。