軟件工程第1次作業
要求0:
作業地址:【https://edu.cnblogs.com/campus/nenu/2016CS/homework/2110】
要求1:
https://git.coding.net/Antidotes/softwareFirstHomework.git git倉庫地址:【https://git.coding.net/Antidotes/softwareFirstHomework.git】
https://git.coding.net/Antidotes/softwareFirstHomework.git
要求2:
1.
PSP階段 |
所花時間百分比(807 / min) |
預計所花時間(350/min) |
|
計劃 |
28 |
30 |
|
·明確需求和其他相關因素,估計每段時間成本 |
28 |
30 |
|
開發 |
751 |
360 |
|
·需求分析 |
20 |
20 |
|
·生成設計文檔 |
30 |
30 |
|
·設計復審(和同學審核設計文檔) |
20 |
10 |
|
·代碼規範(為目前的開發制定合適的規範) |
30 |
20 |
|
·具體設計 |
功能一 |
25 |
10 |
功能二 |
36 |
10 |
|
功能三 |
30 |
10 |
|
·具體編碼 |
功能一 |
60 |
30 |
功能二 |
120 |
50 |
|
功能三 |
120 |
60 |
|
·代碼復審 |
50 |
30 |
|
·測試(自測、修改代碼、提交修改) |
90 |
40 |
|
報告 |
60 |
30 |
|
·測試報告 |
30 |
5 |
|
·事後總結 |
30 |
25 |
2.分析預估耗時與實際耗時的差距原因:
1.自視甚高,想的過於簡單,沒有認真審題,沒有考慮太多的細節。
2.對語言的不熟悉,換了三種語言才寫出項目的半成品。
要求3:
1.解題思路:
看到作業的第一眼,我其實想用C語言寫。因為覺得有點類似大一學算法做的ACM水題,用結構體排序就可以做到。而且“盲目自信”自己更為熟悉C語言。後來上手敲的時候發現並不是這樣的,字符分割那裏就出了一點問題,反復閱讀題目之後覺得用面向過程語言過於繁瑣。後來我嘗試了PYTHON,還是在符號處理和排序除了問題,這裏體現出我確實對PYTHON沒有學到位…有點丟臉的貼上部分PYTHON代碼。這不是我得意的地方,恰恰相反,這是我失敗的地方,但想通過博客的方式來激勵一下自己,提醒自己要繼續鉆研學習PYTHON。
1 import string 2 3 def processLine(line, wordCounts): 4 line = replacePunctuations(line) 5 words = line.split() 6 for word in words: 7 if word in wordCounts: 8 wordCounts[word] += 1 9 else: 10 wordCounts[word] = 1 11 12 13 def replacePunctuations(line): 14 line = line.replace(string.punctuation,‘ ‘) 15 return line 16 17 18 19 def main(): 20 infile = open("input.txt", ‘r‘) 21 count = 10 22 words = [] 23 data = [] 24 25 # 建立用於計算詞頻的空字典 26 wordCounts = {} 27 for line in infile: 28 # 大寫替換成小寫,方便統計詞頻 29 processLine(line.lower(), wordCounts) 30 # 從字典中獲取數據對 31 pairs = list(wordCounts.items()) 32 # 列表中的數據對交換位置,數據對排序 33 items = [[x, y] for (y, x) in pairs] 34 items.sort() 35 36 for i in range(len(items) - 1, len(items) - count - 1, -1): 37 print(items[i][1] + "\t" + str(items[i][0]) ) 38 data.append(items[i][0]) 39 words.append(items[i][1]) 40 41 infile.close() 42 43 44 if __name__ == ‘__main__‘: 45 main()
最後我選擇了用JAVA語言來完成本次作業,因為利用java語言的map鍵值對,在排序要求上便於操作。但是在寫代碼的時候發現自己還是對面向對象這個概念理解的不到位,這次寫作業很大程度上是為了完成任務,對於抽象出類的概念沒有做好,而且也沒有完成輸入文件名的任務。也希望自己在今後的學習中能夠更上一層樓。因為最近發現校園網不用翻就可以上谷歌,也算是開啟了一扇新世界,本次資料搜索途徑多通過谷歌。
通過分析題目,我覺得首先一點是關於題目中所定義單詞的判斷,這也是一個難點,所以我將其作為了一個單獨的功能類。然後是字符的切割,我利用了正則表達式來區分文件中的符號並將單詞分割出來,還有就是大小寫問題。第一次做的時候忘掉了這點,看到結果以後才想起補充完全。最後就是按功能要求排序。
2.項目的重點難點:
①項目概要:使用JAVA語言完成的單詞詞頻統計。
②項目模塊:一個主類:wf(調用功能)
四個功能類:IsNum(判斷是否是項目中定義的單詞)
FunctionOne(實現功能一)
FunctionOne(實現功能二)
FunctionOne(實現功能三)
③實現過程:
IsNUM類:判斷文件中的單詞是否是項目中定義的單詞
import java.util.regex.Matcher; import java.util.regex.Pattern; public class IsNum { public static boolean isNumeric(String word) { Pattern pattern = Pattern.compile("[a-zA-Z][a-zA-Z0-9]*$"); Matcher isNum = pattern.matcher(word); if(!isNum.matches()) { return false; } return true; } }
FunctionOne類:實現功能一,按文件單詞出現順序排序
package test; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import test.IsNum; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Scanner; import java.util.Set; public class FunctionOne { private static String lw; private static String file = ""; public static void funcOne(String path) throws IOException { FileInputStream inputStream = new FileInputStream(new File(path)); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); while((lw = bufferedReader.readLine())!=null){ file += lw+"\n"; } Scanner scanner=new Scanner(file); //單詞和數量映射表 Map<String, Integer> map = new LinkedHashMap<>(); while(scanner.hasNextLine()) { String line=scanner.nextLine(); line = line.toLowerCase(); String[] lineWords=line.split("\\W+");//用非單詞符來做分割 for(int i=0;i<lineWords.length;i++) { //單詞是否合法 if (IsNum.isNumeric(lineWords[i])) { //如果已經有這個單詞了, if(!("".equals(lineWords[i]))){ Iterator<String> iterator = map.keySet().iterator(); boolean exist = false; while(iterator.hasNext()){ String key = iterator.next(); if(key.equalsIgnoreCase(lineWords[i])) { exist = true; map.put(key, map.get(key) + 1); } } if (exist == false) { map.put(lineWords[i], 1); } } } } } System.out.println("Total words is "+map.size()); System.out.println("----------"); for(Map.Entry<String, Integer> entry : map.entrySet()) { System.out.printf("%-12s %d\n",entry.getKey() ,entry.getValue()); } } }
其中,用到了下面的語句來將單詞全部轉換為小寫。
line = line.toLowerCase();
用到了正則表達式來分割單詞。
String[] lineWords=line.split("\\W+");//用非單詞符來做分割
功能一的實現結果如下(我沒有實現輸入文件名的功能,以後會多加改進):
FunctionTwo類:實現功能二,按照字典序排序
package test; import java.awt.List; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Scanner; public class FunctionTwo { private static String lw; private static String file = ""; public static void funcTwo(String path) throws IOException { FileInputStream inputStream = new FileInputStream(new File(path)); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); while((lw = bufferedReader.readLine())!=null){ file += lw+"\n"; } Scanner scanner=new Scanner(file); //單詞和數量映射表 Map<String, Integer> map = new LinkedHashMap<>(); while(scanner.hasNextLine()) { String line=scanner.nextLine(); line = line.toLowerCase(); String[] lineWords=line.split("\\W+");//用非單詞符來做分割,分割出來的就是一個個單詞 for(int i=0;i<lineWords.length;i++) { if (IsNum.isNumeric(lineWords[i])) { //如果已經有這個單詞了, if(!("".equals(lineWords[i]))){ Iterator<String> iterator = map.keySet().iterator(); boolean exist = false; while(iterator.hasNext()){ String key = iterator.next(); if(key.equalsIgnoreCase(lineWords[i])) { exist = true; map.put(key, map.get(key) + 1); } } if (exist == false) { map.put(lineWords[i], 1); } } } } } System.out.println("Total words is "+map.size()); System.out.println("----------"); sortMap(map); } public static void sortMap(Map<String, Integer> oldMap){ ArrayList<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String,Integer>>(oldMap.entrySet()); Collections.sort(list,new Comparator<Map.Entry<String, Integer>>() { public int compare(Entry<String, Integer> o1,Entry<String,Integer> o2) { return o1.getKey().compareTo(o2.getKey()) ; } }); for(int i = 0; i<list.size(); i++){ System.out.printf("%-12s %d\n",list.get(i).getKey(),+list.get(i).getValue()); } } }
其實功能二和功能一很多地方相類似,不過功能二使用了map鍵值對以及collecions來進行排序。
功能二運行結果如下:
FunctionThree:實現功能三,按給定個數n輸出前n個詞頻最高的單詞,詞頻相同則按字典序輸出
package test; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Scanner; import java.util.TreeMap; public class FunctionThree { private static String lw; private static String file = ""; public void funcThree(String path,int n) throws IOException { FileInputStream inputStream = new FileInputStream(new File(path)); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); while((lw = bufferedReader.readLine())!=null){ file += lw+"\n"; } Scanner scanner=new Scanner(file); //單詞和數量映射表 Map<String, Integer> map = new TreeMap<String,Integer>(); while(scanner.hasNextLine()) { String line=scanner.nextLine(); line = line.toLowerCase(); String[] lineWords=line.split("\\W+");//用非單詞符來做分割,分割出來的就是一個個單詞 for(int i=0;i<lineWords.length;i++) { if (IsNum.isNumeric(lineWords[i])) { //如果已經有這個單詞了, if(!("".equals(lineWords[i]))){ Iterator<String> iterator = map.keySet().iterator(); boolean exist = false; while(iterator.hasNext()){ String key = iterator.next(); if(key.equalsIgnoreCase(lineWords[i])) { exist = true; map.put(key, map.get(key) + 1); } } if (exist == false) { map.put(lineWords[i], 1); } } } } } System.out.println("Total words is "+map.size()); System.out.println("----------"); sortValue(map,n); } public static void sortValue(Map<String, Integer> oldMap,int n){ ArrayList<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String,Integer>>(oldMap.entrySet()); Collections.sort(list,new Comparator<Map.Entry<String, Integer>>() { public int compare(Entry<String, Integer> o1,Entry<String,Integer> o2) { return o2.getValue().compareTo(o1.getValue()); } }); for(int i = 0; i < n; i++){ System.out.printf("%-12s %d\n",list.get(i).getKey(),+list.get(i).getValue()); } } }
功能三運行結果如下:
總結來說,我覺得困難點在文件名的絕對路徑和相對路徑,我嘗試了正則表達式“\\”,可是未能解決。解決以後我會對項目加以更新完善。目前來看,十分慚愧。
3.個人感受
這次項目用時時間長,原因在於我本人對語言的不熟悉和自視甚高。回頭重新看一下會發現C\C++,JAVA,Python這三門語言都沒有學精。在功能實現過程中欠火候,十分不成熟。在搜集資料的時候看到過中文分詞的相關介紹,聯想起之前做的機器人項目,在交互語義訓練中也要去實現這個功能,但是當時只是從網上done下來一個代碼套用了事,現在發現沒有精讀細學真的十分後悔。代碼可以done,項目也可以done,別人腦袋裏的東西如果不真正的去學習,卻是怎麽也done不下來的。深覺現在個人能力之欠缺與思想之淺薄,希望自己以後也能站到一個高度上,不斷進步。
在做項目的過程中也產生了一點想法,現在市場上英語單詞類APP非常多,英語但此類工具書也非常多,其中有關於詞頻的統計想來就是這個項目的應用。又聯想起張邦佐老師在數據倉庫一課中對於“《紅樓夢》後四十回到底是誰寫的?”這個引導問題,如果用調查詞頻的方式,找到作者慣用詞匯,或者說在文言文中關於副詞、語氣詞、賓語前置、定語後置等等的應用頻率,是不是可以通過這樣來鑒別作者呢?當然中華文化博大精深,人類也同樣奇妙,不是通過小小的一方面就可以輕易得出結論的。但是如果可以,我希望以後自己能去研究一下這方面的內容,也算是為今天的後悔找了一顆後悔藥。
聯想到《構建之法》中對於團隊的內容,以及上網瀏覽博客有時會看到“結對項目”這四個字,不禁產生一個想法是如果是團隊合作我應該怎麽去完成這個項目呢?軟件工程說到底不是一個人的軟件工程,是一個團隊的軟件工程。希望以後有機會可以嘗試我的想法。
軟件工程第1次作業