第二周作業wordcount
github項目鏈接https://github.com/liqia/WordCount
1.項目簡介
對程序設計語言源文件統計字符數、單詞數、行數,統計結果以指定格式輸出到默認文件中,以及其他擴展功能,並能夠快速地處理多個文件。
可執行程序命名為:wc.exe,該程序處理用戶需求的模式為:
wc.exe [parameter] [input_file_name]
存儲統計結果的文件默認為result.txt,放在與wc.exe相同的目錄下。
2.項目psp表格
PSP2.1表格
PSP2.1 |
PSP階段 |
預估耗時 (分鐘) |
實際耗時 (分鐘) |
Planning |
計劃 |
60 | 100 |
· Estimate |
· 估計這個任務需要多少時間 |
兩天 | 一天半 |
Development |
開發 |
一天 | 一天 |
· Analysis |
· 需求分析 (包括學習新技術) |
180 | 240 |
· Design Spec |
· 生成設計文檔 |
50 | 60 |
· Design Review |
· 設計復審 (和同事審核設計文檔) |
30 | 30 |
· Coding Standard |
· 代碼規範 (為目前的開發制定合適的規範) |
20 | 60 |
· Design |
· 具體設計 |
100 | 120 |
· Coding |
· 具體編碼 |
240 | 260 |
· Code Review |
· 代碼復審 |
30 | 50 |
· Test |
· 測試(自我測試,修改代碼,提交修改) |
120 | 60 |
Reporting |
報告 |
140 | 100 |
· Test Report |
· 測試報告 |
50 | 30 |
· Size Measurement |
· 計算工作量 |
40 | 60 |
· Postmortem & Process Improvement Plan |
· 事後總結, 並提出過程改進計劃 |
60 | 60 |
3.思路
首先要有對java文件處理的,因為要讀文件還要寫文件;
對字符進行統計,就要會一些正則表達式去處理這些字符串;
為了便於管理項目還要將項目推到GitHub上;
4.程序設計實現
(1)首先要對輸入的參數進行處理,得出要調用哪些功能模塊;
為了滿足需求中的輸出順序,我使用一個特定數組a[參數的個數]來表示每一個可能出現的參數存在不存在,存在則在相應的位置置1,掃描完參數之後,就可以按照需求規定的順序進行處理了。詳情請看代碼
代碼:
public static void main(String[] args) {
int[] canshu=new int[5];//0-4分別表示字符、單詞、行數、代碼行數/空行數/註釋行、遞歸處理 的參數存在不存在
String file = new String();
String outputFile = new String();
String stopListFile = new String();
int flag=0;
for(int i=0;i<args.length;i++) {
if (args[i].equals("-c")) canshu[0]=1;
else if (args[i].equals("-w")) canshu[1]=1;
else if (args[i].equals("-l")) canshu[2]=1;
else if (args[i].equals("-a")) canshu[3]=1;
else if (args[i].equals("-s")) canshu[4]=1;
else if (args[i].equals("-o"))
{
if (i==args.length-1) erro("參數不匹配");
if (Pattern.compile("\\w+\\.txt").matcher(args[i+1]).find())
{
outputFile=args[i+1];
i++;
}
else {
erro("輸出文件名不正確");
}
}
else if (args[i].equals("-e"))
{
if (i==args.length-1) erro("參數不匹配");
if (Pattern.compile("\\w+\\.txt").matcher(args[i+1]).find())
{
stopListFile=args[i+1];
i++;
}
else {
erro("參數不匹配");
}
}
else if (Pattern.compile("(\\w+|\\*)\\.\\w+").matcher(args[i]).find()) {
if (i==0) erro("輸入參數不正確");
flag=1;
file=args[i];
}
else {
erro("參數不匹配");
}
}
if (flag == 0) erro("參數不匹配");
execute(canshu,file,stopListFile,outputFile);
}
(2)按照功能需求編寫各個模塊
將文件中的字符一次性讀到String中:
static public String retext(String fileName) {
if (fileName == null) {
return null;
}
InputStream is = null;
try {
is = new FileInputStream(fileName);
} catch (FileNotFoundException e) {
e.printStackTrace();
erro("找不到指定文件");
}
String text = null;
try {
byte[] b = new byte[is.available()];//available函數將會獲取輸入流中字節總數
is.read(b);//根據前面獲得的字節總數,一次性讀出所有字節
text = new String(b);
is.close();
} catch (FileNotFoundException var5) {
var5.printStackTrace();
} catch (IOException var6) {
var6.printStackTrace();
}
return text;
}
統計單詞數,行數:
使用String類中的split函數用正則表達式匹配進行分割
String[] strings = text.split("\\.|,|\\s");
將結果寫入文件:
static public void output(String text, String outputFile) {
try {
FileOutputStream fos = new FileOutputStream(outputFile,true);//第二個參數Ture表示從文件末尾追加寫入
fos.write(text.getBytes());
fos.close();
}
catch (Exception e) {
System.out.println(e.getMessage());
}
}
停用詞表:
首先將詞表文件讀出,然後分割成各個詞,再進行單詞統計的時候判斷單詞時候是否再停用詞表中,以此決定計數與否
返回代碼行/空行/註釋行:
按行讀取文件,
判斷空行的時候就匹配正則表達式中的\s,以及是否是}單獨一行
判斷註釋的時候,對於“//”可以這樣寫正則表達式
\\s*//.*|\\}//.*}
對於“/**/”就需要再匹配到“/*”的時候置一個用於標記的flag為ture,之後的每一行都是註釋,直到匹配到“*/”並將flag置為0;
詳細代碼:
public class CountLine {
private int cntCode=0, cntNode=0, cntSpace=0;
private boolean flagNode = false;
public int[] reA(String fileName) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(fileName));
String line=null;
while((line = br.readLine()) != null)
pattern(line);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("註釋行: " + cntNode);
System.out.println("空行: " + cntSpace);
System.out.println("代碼行: " + cntCode);
System.out.println("總行: " + (cntNode+cntSpace+cntCode));
return new int[]{cntCode, cntSpace, cntNode};
}
private void pattern(String line) {
// TODO Auto-generated method stub
String regxNodeBegin = "\\s*/\\*.*";
String regxNodeEnd = ".*\\*/\\s*";
String regx = "\\s*//.*|\\}//.*}";
String regxSpace = "(\\s*)|(\\s*(\\{|\\})\\s*)";
int i=line.length();
if(line.matches(regxNodeBegin) && line.matches(regxNodeEnd)){
++cntNode;
return ;
}
if(line.matches(regxNodeBegin)){
++cntNode;
flagNode = true;
} else if(line.matches(regxNodeEnd)){
++cntNode;
flagNode = false;
} else if(line.matches(regxSpace)||line.equals("\uFEFF"))
++cntSpace;
else if(line.matches(regx))
++cntNode;
else if(flagNode)
++cntNode;
else ++cntCode;
}
}
5.測試設計過程
考慮到字符串為空的時候可能會有意想不到的bug 所以再測試過程中盡量的會去進行邊界測試。
//測試函數retext
String text = WordCount.retext("src/momo/File.txt");
// String text1 = WordCount.retext(" ");
System.out.println(text);;
//測試函數reWord
int testReWord1 = WordCount.reWorld(null, null);
int testReWord2 = WordCount.reWorld(text, "whetu.txt");
//測試reCount函數
int testReCount = WordCount.reCount(null);
int testReCount1 = WordCount.reCount(text);
//測試reLine函數
int testReLine = WordCount.reLine(null);
int testReLine1 = WordCount.reLine(text);
//測試output函數
WordCount.output(null,"whetu.txt");
WordCount.output("123","whetu.txt");
6.參考文件鏈接
java文件讀取的幾種方式https://www.cnblogs.com/hudie/p/5845187.html
java正則表達式http://www.runoob.com/java/java-regular-expressions.html
java中獲取文件夾或則文件路徑的方法https://www.cnblogs.com/tk55/p/6064160.html
idea如何打包jarhttps://jingyan.baidu.com/article/7e4409531fbf292fc1e2ef51.html
第二周作業wordcount