GitHub地址:https://github.com/Guchencc/WordCount
一.PSP表格
PSP2.1 |
PSP阶段 |
预估耗时 (分钟) |
实际耗时 (分钟) |
Planning |
计划 |
|
|
· Estimate |
· 估计这个任务需要多少时间 |
300 |
440 |
Development |
开发 |
|
|
· Analysis |
· 需求分析 (包括学习新技术) |
20 |
30 |
· Design Spec |
· 生成设计文档 |
10 |
10 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
10 |
10 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
10 |
10 |
· Design |
· 具体设计 |
20 |
30 |
· Coding |
· 具体编码 |
120 |
240 |
· Code Review |
· 代码复审 |
10 |
30 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
20 |
30 |
Reporting |
报告 |
20 |
20 |
· Test Report |
· 测试报告 |
10 |
10 |
· Size Measurement |
· 计算工作量 |
10 |
10 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
10 |
10 |
|
合计 |
270 |
440 |
二、解题思路
了解完题目后,首先回顾了java与文件读写以及目录文件查询等相关函数。改程序是输入命令行然后进行相关操作的,那么首先就需要解析作为主函数参数传入的命令行参数,解析过程中需要区分文件path和命令以及登记相关变量的值,解析完后对变量filelist中的文件进行计数,大体思路如此。
三、程序设计实现过程
本程序实现只用了一个主类WordCount类,其属性如下:
private String filename; //当前计数处理的文件名
private int charcount=0;//字符计数器
private int wordcount=0;//单词计数器
private int linecount=0;//行计数器
private int codeLinecount=0;//代码行计数器
private int blankLinecount=0;//空行计数器
private int commentLinecount=0;//注释行计数器
private ArrayList<String> optlist=new ArrayList<>();//存储输入的命令
private ArrayList<String> stoplist=new ArrayList<>();//存储读取的停用词
private ArrayList<String> filelist=new ArrayList<>();//存储输入的计数文件
private String suffix;//存储输入的通配符后缀
private String outFileName;//存储输入的输出文件名
private String stopFileName;////存储当前处理的的停用词文件名
相关函数如下:
main()为程序主函数。
CommandParser(String[ ] args)函数接受来自主函数的args数组,解析命令行参数并给WordCount类中的相关属性赋值。
Count()函数根据解析后的属性赋值进行计数操作,它会计算所有filelist动态数组中的文件,并根据oplist动态数组中的命令选择输出项。
outprint()函数根据oplist动态数组中的命令选择数据进行文本输出
resetcount()函数重置各类计数器
readStopFile()读取输入的停用词文件中的停用词并添加进stoplist动态数组
findAllFiles()函数递归处理输入的文件路径(包含*.XXX)获取所有以XXX为文件格式的文件路径,并添加进filelist动态数组。
四、代码说明
public void CommandParser(String[] args) { //命令行参数解析,
for(int i=0;i<args.length;i++){
args[i]=args[i].toLowerCase();
if (args[i].equals("-c")||args[i].equals("-l")||args[i].equals("-w")||args[i].equals("-a")||args[i].equals("-s")) //将计数命令直接添加进oplist
optlist.add(args[i]);
else if (args[i].equals("-e")){ //如果输入的命令包含-e 则后面必定是停用词文件路径
i++;
if (args.length>i) {
if (args[i].equals("-o") || args[i].equals("\n")) {
System.out.println("未输入停用单词表文件名!");
return;
}
}else {
System.out.println("未输入停用单词表文件名!");
return;
}
stopFileName=args[i];
optlist.add(args[--i]);
readStopFile();
}
else if (args[i].equals("-o")){ //如果输入的命令包含-o 则后面必定是输出文件路径
if(++i==args.length) {
System.out.println("未输入输出文件名!");
return;
}
outFileName=args[i];
optlist.add(args[--i]);
}
else if (args[i].equals(outFileName)||args[i].equals(stopFileName));
else if (optlist.contains("-s") && args[i].matches(".*\\*[.](txt|c|py|java|cpp)$")){ //根据正则表达式匹配输入的含有通配符的路径
String root="";
suffix=args[i].substring(args[i].indexOf(‘.‘)+1,args[i].length()); //获取想要获取的文件后缀名
root=args[i].replaceAll("\\*[.](txt|c|py|java|cpp)$",""); //获取想要查找含有通配符格式的文件根目录
if (root.length()<1) //如果没有指定目录则从当前目录开始查找
root=System.getProperty("user.dir");
findAllFiles(root);//查找匹配通配符格式的所有文件
}
else if (!optlist.contains("-s")) //如果输入的命令行中无-s 则输入文件名不包含通配符,而是具体的文件路径,直接添加进filelist中
filelist.add(args[i]);
}
}
public void Count() throws Exception {
String str="";
boolean isstop=false;
for (int i=0;i<filelist.size();i++){ //遍历待统计文件数组,并根据相关名词定义进行计数
String path=filelist.get(i);
filename=path.substring(path.lastIndexOf(‘\\‘)+1,path.length());
BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(filelist.get(i))));
while((str=br.readLine())!=null) {
if (str.trim().replaceAll("(//.*|/\\*.*\\*/|/\\*.*|\\*/|\\{|\\})","").length()>1)
codeLinecount++;
if (str.trim().matches("^(//|/\\*).*") || str.trim().matches("^[!-~](//.*|/\\*.*\\*/)") || str.trim().matches("\\*/")){
commentLinecount++;
}
if(str.matches("\\s*") || (str.trim().length()==1 && (str.trim().charAt(0)>0x21 && str.trim().charAt(0)<0x7F)))
blankLinecount++;
linecount++;
charcount+=str.length();
String[] words=str.trim().split("\\s|,");
if (optlist.contains("-e")){ //如果命令包含-e 则遍历单词,若遇到与stoplist中相同的单词则不进行word计数
for(String word:words) {
for (String stopword : stoplist) {
if (word.equals(stopword))
isstop = true;
}
if (!isstop && !word.equals(""))
wordcount++;
isstop = false;
}
}
else {
for (String word:words)
if (!word.equals("")) //如果命令不包含-e 则直接对单词计数
wordcount++;
}
isstop=false;
}
charcount=charcount+linecount-1; // \r\t
if (optlist.contains("-c")){ //根据oplist中的统计命令选择输出结果
System.out.println(filename+","+"字符数:"+charcount);
}
if (optlist.contains("-w")){
System.out.println(filename+","+"单词数:"+wordcount);
}
if (optlist.contains("-l")){
System.out.println(filename+","+"行数:"+linecount);
}
if (optlist.contains("-a")){
System.out.println(filename+","+"代码行/空行/注释行:"+codeLinecount+"/"+blankLinecount+"/"+commentLinecount);
}
outprint(); //记录统计结果
resetCount(); //重置计数器
}
}
public void outprint(){
File file=null;
String str="";
if (!optlist.contains("-c")&&!optlist.contains("-w")&&!optlist.contains("-l")&&!optlist.contains("-a")){
System.out.println("无统计操作,无输出项!");
return;
}
if(optlist.contains("-o") && outFileName!=null)
file = new File(outFileName); //如果指定输出文件路径,则在相应路径输出统计结果
else
file = new File("result.txt"); //否则在当前路径下的result.txt文件中输出。
try{
FileWriter fw=new FileWriter(file,true);
PrintWriter pw=new PrintWriter(fw);
if(!file.exists()){
file.createNewFile();
}
if (optlist.contains("-c")) //根据oplist中的命令选择记录统计结果
str+=filename+","+"字符数:"+charcount+"\r\n";
if (optlist.contains("-w"))
str+=filename+","+"单词数:"+wordcount+"\r\n";
if (optlist.contains("-l"))
str+=filename+","+"行数:"+linecount+"\r\n";
if (optlist.contains("-a"))
str+=filename+","+"代码行/空行/注释行:"+codeLinecount+"/"+blankLinecount+"/"+commentLinecount+"\r\n";
pw.write(str);
pw.close();
fw.close();
}catch (Exception e){
System.out.println("输出文件失败!");
}
}
public void readStopFile(){
String str="";
String[] stopwords;
try {
BufferedReader bf = new BufferedReader(new InputStreamReader(new FileInputStream(stopFileName)));
while ((str = bf.readLine()) != null) { //遍历输入的停用词文件并登记停用词
stopwords = str.trim().split("\\s");
Collections.addAll(stoplist, stopwords);
}
}catch (Exception e){
System.out.println("读取停用词表错误!");
}
}
public void findAllFiles(String path){
File file=new File(path);
if (!file.isDirectory()){
String filename=file.getName();
if (filename.substring(filename.indexOf(‘.‘)+1,filename.length()).equals(suffix)) //将文件后缀与提取的通配符后缀比较,若相同则将该文件路径加入filelist
filelist.add(file.getAbsolutePath());http://blog.csdn.net/zamamiro/article/details/70172900
} else if (file.isDirectory()){
for (File f:file.listFiles())
findAllFiles(f.getAbsolutePath()); //递归遍历文件夹与文件
}
}
五、测试设计过程
还未完成
六、参考文献链接
https://baike.baidu.com/item/正则表达式/1700215?fr=aladdin
http://www.cnblogs.com/ningjing-zhiyuan/p/8563562.html
http://blog.csdn.net/zamamiro/article/details/70172900
http://blog.csdn.net/honjane/article/details/40739337