1. 程式人生 > >軟件工程:java實現wordcount基本功能

軟件工程:java實現wordcount基本功能

param process mar 一個 match sig str 需求 war

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] 這個參數單獨使用。如果命令行有這個參數,則程序會顯示圖形界面,用戶可以通過界面選取單個文件,程序就會顯示文件的字符數、行數等全部統計信息。(未完成)

三:設計思路

  1. 獲取輸入命令行參數,利用正則表達式校驗輸入命令行是否符合格式

  2. 如果輸入命令符合格式要求則利用split(" ")按照空格將命令拆開並存儲於數組

  3. 獲取命令數組的最後一個元素,即為待統計的文件名或目錄

  4. 若輸入為文件則直接進行統計,若輸入為目錄則通過遞歸處理目錄下的文件 

  5. 輸入參數[-c] [-w] [-l] [-a] 初始值設為false,一旦輸入將值置為true以此選擇性地顯示

  6. 根據不同的命令對數據進行相應的處理

    • 字符數:獲取每行的字符數,逐行疊加

    • 詞的數目:獲取每行除去空格的字符數,逐行疊加
    • 行數:利用readline()不為 null,逐行疊加

    • 空行:利用正則表達式統計只含"{"或 "}"或 "\n"的行數
    • 註釋行:統計除去"//"、"{//"、"/*"開頭、"*/"結尾、"/* 單行註釋 */"、"/*多行註釋*/"

    • 代碼行:總行數除去代碼行和空行即可得

四:設計思路

技術分享圖片

五:代碼說明

程序入口,獲取輸入命令行,檢驗後若符合格式,則將命令解析並調用相關功能函數

 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+"\n空行:"+blankLine+"\n註釋行:"+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:\test\test1.txt

  文件截圖:

技術分享圖片

  測試結果:

技術分享圖片

  • 根據文件路徑統計(遞歸處理)

  輸入命令:

wc -s -c -l -w -a  E:\test

  文件截圖:

  E:\test\test1.txt

技術分享圖片

  E:\test\seles\test2.txt

技術分享圖片

  測試結果:

技術分享圖片

七:PSP時間統計

PSP2.1Personal 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的相關內容,同時又發現了許多新的問題,在解決問題的過程受益匪淺。

軟件工程:java實現wordcount基本功能