第二周作业
一、GitHub地址
https://github.com/xuhao97/wordcount
二、PSP表格
|
PSP2.1 |
PSP阶段 |
预估耗时 (分钟) |
实际耗时 (分钟) |
|
Planning |
计划 |
30 |
30 |
|
· Estimate |
· 估计这个任务需要多少时间 |
1day |
-- |
|
Development |
开发 |
-- |
-- |
|
· Analysis |
· 需求分析 (包括学习新技术) |
180 |
300 |
|
· Design Spec |
· 生成设计文档 |
15 |
20 |
|
· Design Review |
· 设计复审 (和同事审核设计文档) |
-- |
-- |
|
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
-- |
-- |
|
· Design |
· 具体设计 |
40 |
30 |
|
· Coding |
· 具体编码 |
200 |
300 |
|
· Code Review |
· 代码复审 |
100 |
50 |
|
· Test |
· 测试(自我测试,修改代码,提交修改) |
140 |
200 |
|
Reporting |
报告 |
40 |
30 |
|
· Test Report |
· 测试报告 |
40 |
50 |
|
· Size Measurement |
· 计算工作量 |
20 |
15 |
|
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
20 |
20 |
|
|
合计 |
885 |
1045 |
三、解题思路
1.所有参数都是通过main函数的args[]数组传入的,所以只要通过对args[]数组的内容进行判断,就可以知道要执行的操作。
2.对于基本功能,通过逐行读取文本,可以比较容易的判断行数和字符数,单词只要通过split函数进行分割即可。若要把输出结果到txt文本,只要在统计结果时将结果打印并将输出流定位到txt文本上。
3.附加功能:(1)注释行的统计比较麻烦,因为情况太多,但是可以把一些情况合并,因为/*的优先级是非常高的,只要出现/*,后面必定是注释,所以可以做个标记,标记此时遇到的行均视为注释行。除非再遇到*/。
(2)对于停用词表,想法是取出每个停用单词,然后在统计单词的时候,做个判断,如果遇到停用词,则不计这个单词即可。
(3)循环执行目录下所有符合的文件:这个需要遍历文件,把所有文件的地址先保存起来,然后就和前面基本无异,只需一个一个运行即可。
四、程序实现过程
1 首先是对参数的处理
public class wc { static List<String> names = new ArrayList<String>(); public static void main(String[] args) throws IOException { int i,j=0; boolean out=false,stop=false; String pathname=""; String outputpath=""; String stoppath=""; String[] newpath={}; boolean already=false; for(i=0;i<args.length;i++)//先判断是否要输出到文件,以及停用词表 { if(args[i].endsWith(".c")) pathname=args[i]; if(args[i].equals("-o")) { out=true; outputpath=args[i+1]; //获取输出文件位置 } if(args[i].equals("-e")) { stop=true; stoppath=args[i+1]; //获取停用词表位置 } } for(i=0;i<args.length;i++)//这里代码比较冗余,为了简单起见,我对有-s参数的进行了单独处理,因为要处理多个文件 { if(args[i].equals("-s")) { already=true; String path=args[i+1]; //获取文件夹位置 readfile(path); for (j = 0; j < names.size(); j++) { File f = new File(names.get(j)); pathname=names.get(j); for(i=0;i<args.length;i++)//判断传入的参数,并执行相应的步骤 { if(args[i].equals("-c")) c(f,out,pathname,outputpath); if(args[i].equals("-w")) w(f,out,pathname,outputpath,stop,stoppath); if(args[i].equals("-l")) l(f,out,pathname,outputpath); if(args[i].equals("-a")) a(f,out,pathname,outputpath); } } } } File f = new File(pathname); if(!already)//-s以及运行过了,所以这里执行的参数是不含-s的 { for(i=0;i<args.length;i++)//判断传入的参数,并执行相应的步骤 { if(args[i].equals("-c")) c(f,out,pathname,outputpath); if(args[i].equals("-w")) w(f,out,pathname,outputpath,stop,stoppath); if(args[i].equals("-l")) l(f,out,pathname,outputpath); if(args[i].equals("-a")) a(f,out,pathname,outputpath); } } }
2 对基本功能的实现
public static int c(File f,boolean out,String path,String opath){ int num=0; BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(f)); String s = null; while ((s = reader.readLine()) != null){ //读取每一行 num += s.length();//直接计算这一行的字符数 } if(out)//判断是否输出,通过参数传入 { FileWriter fw = null;//追加输出 File ft = new File(opath); fw = new FileWriter(ft, true); PrintWriter pw = new PrintWriter(fw); pw.println(path+",字符数:"+num); pw.flush(); try { fw.flush(); pw.close(); fw.close(); } catch (IOException e) { e.printStackTrace(); } } } catch (FileNotFoundException e2) { e2.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } finally{ try{ reader.close(); } catch (IOException e1) { e1.printStackTrace(); } } return num; } public static int w(File f,boolean out,String path,String opath,boolean stop,String spath){ int word=0; int k=0,j=0; BufferedReader reader = null; BufferedReader stopreader = null; String sl; String[] wordlist={}; String[] stoplist={}; if(stop) { try { stopreader = new BufferedReader(new FileReader(spath)); while ((sl = stopreader.readLine()) != null){ stoplist=sl.split("\\s+");}//用正则表达式进行判断,\\s代表一切空白,+代表多个。可以比较容易的得出单词个数。 } catch (FileNotFoundException e2) { e2.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } } try { reader = new BufferedReader(new FileReader(f)); String s = null; while ((s = reader.readLine()) != null){ if(s.charAt(0)==32||s.charAt(0)==44||s.charAt(0)==9) word=word-1;//如果第一个是空格,则单词数需要减一,因为spilt会把空格前作为一个单词 word += s.split(",+|\\s+").length; if(stop) { wordlist=s.split(",+|\\s+");//取出单词 for(k=0;k<wordlist.length;k++) { for(j=0;j<stoplist.length;j++) {wordlist[k]=wordlist[k].trim(); if(wordlist[k].equals(stoplist[j]))//如果单词相同,则减去一(因为之前统计了一次) { word = word-1; } } } } } if(out)//输出 { FileWriter fw = null; File ft = new File(opath); fw = new FileWriter(ft, true); PrintWriter pw = new PrintWriter(fw); pw.println(path+",单词数:"+word); pw.flush(); try { fw.flush(); pw.close(); fw.close(); } catch (IOException e) { e.printStackTrace(); } } } catch (FileNotFoundException e2) { e2.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } finally{ try{ reader.close(); } catch (IOException e1) { e1.printStackTrace(); } } return word; } public static int l(File f,boolean out,String path,String opath){ int line=0; BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(f)); String s = null; while ((s = reader.readLine()) != null)//读取一行则加一即可 line +=1; if(out) { FileWriter fw = null; File ft = new File(opath); fw = new FileWriter(ft, true); PrintWriter pw = new PrintWriter(fw); pw.println(path+",行数:"+line); pw.flush(); try { fw.flush(); pw.close(); fw.close(); } catch (IOException e) { e.printStackTrace(); } } } catch (FileNotFoundException e2) { e2.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } finally{ try{ reader.close(); } catch (IOException e1) { e1.printStackTrace(); } } return line; }
3 对注释的判断
public static void a(File f,boolean out,String path,String opath){ int blankline=0; int noteline=0; int codeline=0; int line=0; int i=0; String sa = null; boolean notnote=true;//这里判断是否是/*后面的行,因为这后面的行均是注释行,所以用此标记前面是否出现了/*且没有出现*/ BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(f)); while ((sa = reader.readLine()) != null) { line +=1;//统计总行数 if(sa.length()<=1) blankline +=1;//如果一行字符数少于一,直接视为空白行,即使有可能此行在/*....*/中 else{ if((!sa.contains("*/"))&&!notnote) noteline+=1; //这里是不同情况的判断 if(sa.contains("/*")&¬note) { notnote=false; noteline+=1; } if(sa.contains("//")&¬note) noteline+=1; if(sa.contains("*/")&&!notnote) { noteline+=1; notnote=true; } } } codeline=line-noteline-blankline;//代码行直接用总行数减去空白行和注释行就行了 if(out) { FileWriter fw = null; File ft = new File(opath); fw = new FileWriter(ft, true); PrintWriter pw = new PrintWriter(fw); pw.println(path+",代码行/空行/注释行:"+codeline+"/"+blankline+"/"+noteline); pw.flush(); try { fw.flush(); pw.close(); fw.close(); } catch (IOException e) { e.printStackTrace(); } } } catch (FileNotFoundException e2) { e2.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } finally{ try{ reader.close(); } catch (IOException e1) { e1.printStackTrace(); } } }
4 寻找文件夹下所有符合的文件
public static void readfile(String filepath) throws FileNotFoundException, IOException {//遍历文件的过程 int i; try { File file = new File(filepath); if (!file.isDirectory()) {//如果不是文件夹,直接获取文件名字并判断 if(file.getAbsolutePath().endsWith(".c")) { names.add(file.getAbsolutePath()); } } else if (file.isDirectory()) {//如果是文件夹,则进入文件夹,并在文件夹中的文件夹进行递归调用 String[] filelist = file.list(); for (i = 0; i < filelist.length; i++) { File readfile = new File(filepath + "\\" + filelist[i]); if (!readfile.isDirectory()) { if(readfile.getAbsolutePath().endsWith(".c")) { names.add(readfile.getAbsolutePath()); } } else if (readfile.isDirectory()) { readfile(filepath + "\\" + filelist[i]);//递归调用 } } } } catch (FileNotFoundException e) { System.out.println("readfile() Exception:" + e.getMessage()); } }
五 测试设计
采用bat脚本测试,脚本如下:
wc.exe -c -l -w testf1.c 测试基本功能
wc.exe -c -l -w testf1.c -o result.txt 测试基本功能,并将结果输出到result.txt
wc.exe -c -l -s D:\\workspace\\wordcount 测试是否能遍历文件夹中所有的.c文件
wc.exe -e stoplist.txt teste.c 测试停用词表功能
wc.exe -a test1.c 测试注释功能
wc.exe -c -l -w -e stoplist.txt -s D:\\workspace\\wordcount -o result.txt 测试全部功能
脚本及测试结果见github文件夹下
六、参考文献链接
1.http://blog.csdn.net/ycy0706/article/details/45457311
2.http://www.runoob.com/java/java-filewriter.html
3.https://www.cnblogs.com/wangcp-2014/p/5851986.html
4.http://blog.csdn.net/tanga842428/article/details/52810869
浙公网安备 33010602011771号