第1次作業


要求0:作業要求地址【https://edu.cnblogs.com/campus/nenu/2016CS/homework/2110

要求1:git倉庫地址【https://git.coding.net/Jingr98/wf.git】

要求2:

1.PSP階段表格

SP2.1

任務內容

計划共完成需要的時間(min)

實際完成需要的時間(min)

  Planning

計划

40

50

Estimate

估計這個任務需要多少時間,並規划大致工作步驟

40

50

  Development

開發

810

1030

 Analysis

需求分析 (包括學習新技術)

90

130

Design Spec

生成設計文檔

40

40

Design Review

設計復審 (和同事審核設計文檔)

0

0

 Coding Standard

代碼規范 (為目前的開發制定合適的規范)

0

40

Design

具體設計

90

90

Coding

具體編碼

480

600

 Code Review

代碼復審

40

50

Test

 測試(自我測試,修改代碼,提交修改)

70

80

  Reporting

報告

180

210

Test Report

測試報告

100

120

Size Measurement

計算工作量

40

40

Postmortem & Process Improvement Plan

事后總結, 提出過程改進計划

40

50

 

功能模塊

具體階段

預計時間(min)

實際時間(min)

  功能1

具體設計

具體編碼

測試完善

20

130

20

30

200

25

功能2

具體設計

具體編碼

測試完善

30

140

20

15

150

25

  功能3

具體設計

具體編碼

測試完善

40

210

30

 

45

250

30

2.分析預估耗時和實際耗時的差距原因:

(1)在分析預估耗時時,沒有過多考慮編程中的細節問題。編程過程中不斷有新的問題出現。

(2)對Java語言掌握不夠熟練,編程中學習的時間較長

(3)最主要的原因就是一開始審題不清,沒有考慮到輸出樣例格式的問題。導致項目將要完工時又要整改很多地方,浪費了好多時間。

要求3:

1.解題思路描述

(1)看到題目后,我想了一下這個程序大致有三個步驟:讀取文本、統計單詞、(排序)輸出。有了這個框架后,我從最簡單的功能1嘗試編寫,在獲取到文本內容需要對字符串進行分割時我遇到了一些問題(因為不是很熟悉正則表達式),所以查閱了相關教程,自己嘗試寫了一下可以達到預期效果,但是需要兩次正則表達式的運用(一是對字符串按空格和非字母數字符號進行分割得到字符串數組,二是對得到的字符串數組通過字母開頭規則過濾掉那些非法單詞),自我感覺這里編寫的不是太好。實現了功能1后我開始看功能2,發現只要得到文件夾下的文件名數組,排序后返回指定文件路徑后就可以參照功能1的實現。功能3的話只要在前者的基礎上傳入參數-n,對list進行排序后根據-n輸出結果。

(2)最初編寫時我是把功能1和功能2寫在了一起,即用一個count()函數實現兩個功能。功能1直接調用count()就可以實現詞頻統計,功能2則需要先調用readDir()和setpath()方法得到指定文件路徑,然后再調用count()就可以了。功能3則是用count( int n )實現。但是后來我仔細看了題目后發現,兩者的輸出樣例是不一樣的!發現了這個問題后,我本來想寫兩個輸出結果的方法分別對應上述兩種情況,但是嘗試了一下報了很多錯誤,就不敢大改了,只能選擇把兩種情況完全分開處理,於是就有了現在的 countFile()和countDir()分別對應功能1和功能2,countNum()對應功能3。這樣雖然解決了樣例輸出的問題,但是代碼重復量真的很大。

2.代碼介紹

(1)困難點:功能1主要是對字符串的處理(正則表達式的運用),如何得到合法單詞;功能2主要是獲取某文件夾下的所有文件名,並按照文件名排序后返回指定文件,其余就參照功能1的實現;功能3主要是對詞頻進行排序,並按照參數進行輸出。其實我感覺這三個功能分開來寫不是很難,對我來說,最困難的就是如何減少代碼的重復。三個功能明顯有重復的部分,應該把哪些部分拎出來寫成公共的方法,是我應該繼續思考的!

(2)代碼片段

簡單介紹一下我的代碼,總體上用Java寫了兩個類:wf類(包含各種功能方法)和wfTest類(分情況對wf類里的方法進行調用,用來測試)。

1) isLegal()函數:判斷是否為合法單詞

 1 public boolean isLegal(String word) {  2         String regex="^[a-zA-Z][a-zA-Z0-9]*$";  3         Pattern p = Pattern.compile(regex);  4         Matcher m =p.matcher(word);  5         if(m.matches()) {  6             return true;  7         }else {  8             return false;  9  } 10     }

2) readDir()函數:獲取文件夾下所有文件的文件名,對數組進行排序並返回第一個元素

 1 public String readDir(String filepath){  2         File file = new File(filepath);  3         String[] filelist = file.list();  4         String[] namelist = new String [filelist.length];  5         for(int i=0;i<filelist.length;i++) {  6             File readfile = new File(filepath+"\\"+filelist[i]);  7             namelist[i]=readfile.getName();  8  }  9         List<String> list = (List<String>)Arrays.asList(namelist); 10  Collections.sort(list); 11         String[] paths = list.toArray(new String[0]); 12             
13         return paths[0]; 14     }

3) countFile()函數:當輸入格式為【wf -c 文件名 】時調用,並輸出結果

 

 1 public void countFile() {  2         try {  3             FileInputStream inputStream = new FileInputStream(new File(path));  4             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));  5             //將文件內容存入words中
 6             while((lineword=bufferedReader.readLine())!=null) {  7                 words+=lineword+"\n";  8  }  9             //全部轉換成小寫,達到不區分大小寫的目的
10             String str=words.toString().toLowerCase(); 11             //分割字符串並存入數組
12             String[] word = str.split("[^a-zA-Z0-9]|\\ "); 13             int num =0; 14             Map<String,Integer> myMap = new TreeMap<String,Integer>(); 15             //遍歷數組將其存入Map<String,Integer>中
16             for(int i=0;i<word.length;i++) { 17                 //首先判斷是否為合法單詞,合法則存入map中 
18                 if(isLegal(word[i])) { 19                     if(myMap.containsKey(word[i])) { 20                         num = myMap.get(word[i]); 21                         myMap.put(word[i], num+1); 22  } 23                     else { 24                         myMap.put(word[i], 1); 25  } 26  } 27  } 28             //將map.entrySet()轉換成list
29             List<Map.Entry<String, Integer>> list =new ArrayList<Map.Entry<String,Integer>>(myMap.entrySet()); 30             //輸出結果
31             System.out.println("total"+" "+list.size()+"\n"); 32 // for(int i=0;i<list.size();i++) { 33 // Map.Entry<String, Integer> e =list.get(i); 34 // System.out.println(e.getKey()+" "+e.getValue()); 35 // }
36             for(int i=0;i<word.length;i++) { 37                 if(myMap.containsKey(word[i])) { 38                     System.out.printf("%-14s%d\n",word[i],myMap.get(word[i]));
39 myMap.remove(word[i]); 40 } 41 } 42 bufferedReader.close(); 43 }catch(FileNotFoundException e) { 44 e.printStackTrace(); 45 }catch(IOException e) { 46 e.printStackTrace(); 47 } 48 }

 

 

 

4) countDir()函數:當輸入格式為【wf -f 文件路徑 】時調用,並輸出結果。(和countFile函數基本一致,只是輸出格式上有些不同)

 1 public void countDir() {  2         try {  3             FileInputStream inputStream = new FileInputStream(new File(path));  4             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));  5             //將文件內容存入words中
 6             while((lineword=bufferedReader.readLine())!=null) {  7                 words+=lineword;  8  }  9             //全部轉換成小寫,達到不區分大小寫的目的
10             String str=words.toString().toLowerCase(); 11             //分割字符串並存入數組
12             String[] word = str.split("[^a-zA-Z0-9]|\\ "); 13             int num =0; 14             Map<String,Integer> myMap = new TreeMap<String,Integer>(); 15             //遍歷數組將其存入Map<String,Integer>中
16             for(int i=0;i<word.length;i++) { 17                 //首先判斷是否為合法單詞 
18                 if(isLegal(word[i])) { 19                     if(myMap.containsKey(word[i])) { 20                         num = myMap.get(word[i]); 21                         myMap.put(word[i], num+1); 22  } 23                     else { 24                         myMap.put(word[i], 1); 25  } 26  } 27  } 28             //將map.entrySet()轉換成list
29             List<Map.Entry<String, Integer>> list =new ArrayList<Map.Entry<String,Integer>>(myMap.entrySet()); 30             //輸出結果
31             System.out.println("total"+" "+list.size()+" words"); 32             for(int i=0;i<list.size();i++) { 33                 Map.Entry<String, Integer> e =list.get(i); 34                 System.out.println(e.getKey()+" "+e.getValue()); 35  } 36  bufferedReader.close(); 37         }catch(FileNotFoundException e) { 38  e.printStackTrace(); 39         }catch(IOException e) { 40  e.printStackTrace(); 41  } 42     }
View Code

5) countNum()函數:當輸入格式為【wf -f 文件路徑 -n 數量】或者【wf -c 文件名 -n 數量】或者【wf -n 數量 -c 文件名】或者【wf -n 數量 -f 文件路徑】時調用,並輸出結果

 1 public void countNum(int n) {  2         try {  3             FileInputStream inputStream = new FileInputStream(new File(path));  4             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));  5             //將文件內容存入words中
 6             while((lineword=bufferedReader.readLine())!=null) {  7                 words+=lineword+"\n";  8  }  9             //全部轉換成小寫,達到不區分大小寫的目的
10             String str=words.toString().toLowerCase(); 11             //分割字符串並存入數組
12             String[] word = str.split("[^a-zA-Z0-9]|\\ "); 13             int num =0; 14             Map<String,Integer> myMap = new TreeMap<String,Integer>(); 15             //遍歷數組將其存入Map<String,Integer>中
16             for(int i=0;i<word.length;i++) { 17                 //首先判斷是否為合法單詞 
18                 if(isLegal(word[i])) { 19                     if(myMap.containsKey(word[i])) { 20                         num = myMap.get(word[i]); 21                         myMap.put(word[i], num+1); 22  } 23                     else { 24                         myMap.put(word[i], 1); 25  } 26  } 27  } 28             //將map.entrySet()轉換成list
29             List<Map.Entry<String, Integer>> list =new ArrayList<Map.Entry<String,Integer>>(myMap.entrySet()); 30             //通過比較器實現排序
31             Collections.sort(list,new Comparator<Map.Entry<String, Integer>>(){ 32                 public int compare(Entry<String,Integer> e1,Entry<String,Integer> e2) { 33                     return e2.getValue().compareTo(e1.getValue()); 34  } 35  }); 36             //輸出結果
37             System.out.println("Total words is "+list.size()); 38             System.out.println("----------"); 39             for(int i=0;i<n;i++) { 40                 Map.Entry<String, Integer> e =list.get(i); 41                 System.out.printf("%-14s%d\n",e.getKey(),e.getValue());
42 } 43 bufferedReader.close(); 44 }catch(FileNotFoundException e) { 45 e.printStackTrace(); 46 }catch(IOException e) { 47 e.printStackTrace(); 48 } 49 }

6)setpath()函數:創建對象時若沒有傳入路徑,則給變量path賦值

 public void setpath(String path) { this.path=path; } 

7)最后,在wfTest類里,我通過 if else 語句對控制台輸入的字符串分情況討論,調用相應的方法

 1 package wf;  2 import java.util.*;  3 
 4 public class wfTest{  5     public static void main(String[] args) {  6         Scanner input = new Scanner(System.in);  7         String str = "";  8         str = input.nextLine();  9         String[] splt = str.split(" "); 10  String path; 11         int num=splt.length; 12         if(num==3) { 13             
14             if(splt[1].equals("-c")) { 15                 path=splt[2]; 16                 wf test = new wf(path); 17  test.countFile(); 18             }else if(splt[1].equals("-f")){ 19                 
20                 wf test = new wf(); 21                 path=test.readDir(splt[2]); 22 // System.out.println(splt[2]);
23                 test.setpath(splt[2]+"\\"+path); 24  test.countDir(); 25             }else { 26                 System.out.println("輸入格式有錯誤"); 27  } 28            
29         }else if(num==5) { 30             if(splt[1].equals("-f")&&splt[3].equals("-n")) { 31                 wf test = new wf(); 32                 path=test.readDir(splt[2]); 33                 test.setpath(splt[2]+"\\"+path); 34                 test.countNum(Integer.parseInt(splt[4])); 35             }else if(splt[1].equals("-c")&&splt[3].equals("-n")) { 36                 path=splt[2]; 37                 wf test = new wf(path); 38                 test.countNum(Integer.parseInt(splt[4])); 39             }else if(splt[1].equals("-n")&&splt[3].equals("-c")) { 40                 path=splt[4]; 41                 wf test = new wf(path); 42                 test.countNum(Integer.parseInt(splt[2])); 43             }else if(splt[1].equals("-n")&&splt[3].equals("-f")) { 44                 wf test = new wf(); 45                 path=test.readDir(splt[4]); 46                 test.setpath(splt[4]+"\\"+path); 47                 test.countNum(Integer.parseInt(splt[2])); 48             }else { 49                 System.out.println("輸入格式有錯誤"); 50  } 51         }else { 52             System.out.println("輸入格式有錯誤"); 53  } 54         
55  input.close(); 56  } 57 }

8)運行結果展示:

此截圖是在eclipse平台上運行的效果,但是項目里已經生成 wf.exe 執行文件,可以在控制台進行測試(這是我第一次用jar包通過exe4j生成可執行文件,因為在exe4j上忘記選擇生成控制台程序(默認是gui程序),所以在這里糾結了好久,真的是。。。為了避免大家犯同樣的錯誤,在此誠摯地推薦一篇相關博客:https://blog.csdn.net/u011752272/article/details/80697198)

作業輸出樣例:

測試輸出樣例:

3.個人感想

       通過此次項目的經歷,我覺得代碼的規范性很重要。這次作業我相當於寫了兩個版本,最終的代碼是在初期代碼的基礎上改了很多,這個改代碼的時間真的快趕上我寫出程序的時間了。一開始自己沒想着如何整體對項目結構進行設計,就一步步按照自己的想法寫完了,但是回過頭去改的時候,發現結構有些亂,改的時候需要兼顧很多東西,真的不太好。這讓我想到了《構建之法》第四章所講的有關代碼規范的重要性,現在看自己編寫的代碼都別扭與復雜,更別說在合作的過程中他人看自己的代碼的感受了。希望自己可以通過此次作業,在這方面有所改進。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM