WC个人项目(Java)
WC.exe
GitHub链接:https://github.com/yeyuyu/ruanjiangongcheng
1.项目要求
实现一个统计程序,它能正确统计程序文件中的字符数、单词数、行数,以及还具备其他扩展功能,并能够快速地处理多个文件。
具体功能要求:
程序处理用户需求的模式为:
wc.exe [parameter] [file_name]
基本功能列表:(已完成)
wc.exe -c file.c //返回文件 file.c 的字符数
wc.exe -w file.c //返回文件 file.c 的词的数目
wc.exe -l file.c //返回文件 file.c 的行数
扩展功能:(已完成)
-s 递归处理目录下符合条件的文件。
-a 返回更复杂的数据(代码行 / 空行 / 注释行)。
空行:本行全部是空格或格式控制字符,如果包括代码,则只有不超过一个可显示的字符,例如“{”。
代码行:本行包括多于一个字符的代码。
注释行:本行不是代码行,并且本行包括注释。一个有趣的例子是有些程序员会在单字符后面加注释:
} //注释
在这种情况下,这一行属于注释行。
[file_name]: 文件或目录名,可以处理一般通配符。
高级功能:(未完成)
-x 参数。这个参数单独使用。如果命令行有这个参数,则程序会显示图形界面,用户可以通过界面选取单个文件,程序就会显示文件的字符数、行数等全部统计信息。
需求举例:
wc.exe -s -a *.c
返回当前目录及子目录中所有*.c 文件的代码行数、空行数、注释行数。
2.解题思路
太久没有打代码,看到题目后去网上搜了很多开源代码,但不允许copy,就理解了几份开源代码的思路,再整合为自己用,设计了基本模块和框架。接着分两大类,先是写出main函数中基本功能的函数,再在control类具体实现出来。后面又补充-s功能和-a功能。
3.设计实现过程
代码分成两个类:
1.Main类实现输入命令。
2.Control类实现基本功能,-s功能,-a功能。
4.关键代码
4.1 main类
public static void main(String[] args) { System.out.println("----------------------命令格式----------------------"); System.out.println("-c [文件路径] \\返回字符数"); System.out.println("-w [文件路径] \\返回词的数目"); System.out.println("-l [文件路径] \\返回行数"); System.out.println("-a [文件路径] \\返回空行、代码行、注释行的数目"); System.out.println("-s [文件路径] \\递归处理目录下符合条件的文件"); System.out.println("----------------------------------------------------"); System.out.print("输入命令:"); Scanner input = new Scanner(System.in); String in = input.nextLine(); control cont=new control(); try { cont.sort(in); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
4.2 基本功能
//统计字符数 void charcount(String filename) throws IOException{ BufferedReader brin = new BufferedReader(new FileReader(filename)); String str1=""; while ((str1=brin.readLine())!=null){ charnums+=str1.length(); } System.out.println("字符数为:"+charnums); brin.close(); } //统计行数 void rowcount(String filename) throws IOException{ BufferedReader brin = new BufferedReader(new FileReader(filename)); String str1=""; while ((str1=brin.readLine())!=null){ rownums+=1; } System.out.println("行数为:"+rownums); brin.close(); } //统计词数 void wordcount(String filename) throws IOException{ BufferedReader brin = new BufferedReader(new FileReader(filename)); String str1=""; int flag=0;//单词是否连续 while ((str1=brin.readLine())!=null){ for(int i=0;i<str1.length();i++){ if(str1.charAt(i)>='a'&&str1.charAt(i)<='z'||str1.charAt(i)>='A'&&str1.charAt(i)<='Z'){ flag=1; } else{ if(flag==1){ wordnums++; flag=0; } } } } System.out.println("单词数为:"+wordnums); brin.close(); }
4.3 -s功能
//递归操作 void readDirectory(String filename1){ String path=""; int i=0; String [] strs=filename1.split("\\\\"); String filename=strs[strs.length-1]; for(;i<strs.length-2;i++){ path+=strs[i]+"\\"; } path+=strs[i]; if(0==filename.compareTo("*.*")||0==filename.compareTo("*.?")||0==filename.compareTo("?.*")){ File filedirectory = new File(path); if (filedirectory.exists()) { File[] files = filedirectory.listFiles(); if (null == files || files.length == 0) { System.out.println("文件夹是空的!"); return;} else{ for (File file : files) { //遍历路径里的文件夹 if (file.isDirectory()) { System.out.println(file.getName()+"[文件夹]"); readDirectory(file.getAbsolutePath()+"\\"+filename); } else { System.out.println(file.getName()); try { charcount(file.toString()); wordcount(file.toString()); rowcount(file.toString()); allcount(file.toString()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("总字符数为:"+charnums); System.out.println("总词数为:"+wordnums); System.out.println("总行数为:"+rownums); System.out.println("总空行数为:"+emptyrownums); System.out.println("总代码行数为:"+coderownums); System.out.println("总注释数为:"+noterownums); } } } } else{ System.out.println("文件不存在!"); } } else{ String filenamesort []=filename.split("\\."); if(filenamesort[0].equals("*")){ String filename2="."+filenamesort[filenamesort.length-1]; File filedirectory2 = new File(path); if (filedirectory2.exists()) { File[] files2 = filedirectory2.listFiles(); if (null == files2 || files2.length == 0) { System.out.println("文件夹是空的!"); return; } else { for (File file2 : files2) { //遍历路径里的文件夹 if (file2.isDirectory()) { readDirectory((file2.getAbsolutePath()+"\\"+filename2)); } else if (file2.getName().contains(filename2)) { System.out.println(file2.getName()); try { charcount(file2.toString()); wordcount(file2.toString()); rowcount(file2.toString()); allcount(file2.toString()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("总字符数为:"+charnums); System.out.println("总词数为:"+wordnums); System.out.println("总行数为:"+rownums); System.out.println("总空行数为:"+emptyrownums); System.out.println("总代码行数为:"+coderownums); System.out.println("总注释数为:"+noterownums); } } } } else { System.out.println("文件不存在!"); } } else if(filenamesort[filenamesort.length-1].equals("*")){ File filedirectory3 = new File(path); if (filedirectory3.exists()) { File[] files3 = filedirectory3.listFiles(); if (null == files3 || files3.length == 0) { System.out.println("文件夹是空的!"); return; } else { for (File file3 : files3) { //遍历路径里的文件夹 if (file3.isDirectory()) { System.out.println(file3.getName()+"[文件夹]"); readDirectory(file3.getPath()+"\\"+filename); } else { if(file3.getName().indexOf(filenamesort[0])==0){ System.out.println(file3.getName()); try { charcount(file3.toString()); wordcount(file3.toString()); rowcount(file3.toString()); allcount(file3.toString()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("总字符数为:"+charnums); System.out.println("总词数为:"+wordnums); System.out.println("总行数为:"+rownums); System.out.println("总空行数为:"+emptyrownums); System.out.println("总代码行数为:"+coderownums); System.out.println("总注释数为:"+noterownums); } } } } } else { System.out.println("文件不存在!"); } } } }
4.4 -a功能
//统计空白,注释,代码行数 void allcount(String filename) throws IOException{ BufferedReader brin = new BufferedReader(new FileReader(filename)); String str1=""; int linenums=0; while ((str1=brin.readLine())!=null){ if(str1.length()==0||str1.length()==1){ emptyrownums++; } else{ for(int i=0;i<str1.length()-1;i++){ if(str1.charAt(i)== '\\' &&str1.charAt(i+1)=='\\'){ if(i==0||i==1){ noterownums++; } } } } linenums++; } if(linenums<noterownums+emptyrownums)coderownums=0; else{coderownums=linenums-noterownums-emptyrownums;} System.out.println("注释行数为:"+noterownums); System.out.println("空行数为:"+emptyrownums); System.out.println("代码行数为:"+coderownums); brin.close(); }
5.测试
5.1 空文件
5.2 只有一个字符的文件
5.3 只有一个词的文件
5.4 只有一行的文件
5.5 源文件
5.6 -s 功能
5.7 代码覆盖率
6.PSP
PSP |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
30 | 30 |
· Estimate |
· 估计这个任务需要多少时间 |
30 | 30 |
Development |
开发 |
1130 | 1260 |
· Analysis |
· 需求分析 (包括学习新技术) |
240 | 200 |
· Design Spec |
· 生成设计文档 |
60 | 90 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
30 | 30 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
60 | 30 |
· Design |
· 具体设计 |
120 | 60 |
· Coding |
· 具体编码 |
300 | 360 |
· Code Review |
· 代码复审 |
120 | 100 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
120 | 300 |
Reporting |
报告 |
120 | 60 |
· Test Report |
· 测试报告 |
60 | 30 |
· Size Measurement |
· 计算工作量 |
30 | 15 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
30 | 15 |
合计 |
1280 | 1350 |
7.项目总结
项目开始遇到很多困难:
1)不会使用Git,刚开始注册GitHub就遇到很多问题,一一百度花了很长时间。刚开始不懂仓库怎么创建,也不知道怎么push上去。后面百度Git教程,粗略学了一下Git的教程,用Git Bush使用命令操作,相对简单。
2)刚开始是模仿几份代码的思路,由于部分思路没有缕清,尝试了多次才吧正确的代码写出来;并且在打码过程中犯了很多低级错误。编码是整个工程耗时最长的部分。
3)没有接触过测试单元,学习如何写测试单元花了一些时间。
之前打码并没有一个完整的流程,这次首次用软件工程思想做一个小项目,虽然做的结果差强人意,用软件工程思想做出来的小项目有点也没有凸显出来,但总是是打开了软件工程的大门。