所謂中文分詞,就是將中文語句中的詞彙切分出來。中文文本自動分詞算法從20世紀80年代以來就一直是研究熱點。分詞技術做爲天然語言處理的基礎環節,同時也是關鍵環節之一,它的質量好壞直接影響到後續處理步驟的效果。java
本文將討論三種基於規則的中文分詞算法,分別是正向最大匹配法、逆向最大匹配法、雙向匹配法,介紹其要點及優缺點,並代碼實現。算法
(1)簡介:事先人工創建好分詞詞典和分詞規則庫,基於字符串匹配進行分詞,要求有足夠大的詞表爲依據。url
(2)優缺點:當分詞詞典所收容的詞較少時,覆蓋率有限致使分詞的正確率低。 spa
(3)算法:正向最大匹配法、逆向最大匹配法、雙向匹配法。設計
切分出單字串,而後和詞庫進行比對,若是是一個詞就記錄下來, 不然經過增長或者減小一個單字,繼續比較,一直還剩下一個單字則終止。指針
設MaxLen表示最大詞長,D爲分詞詞典。code
①從待切分語料中按正向取長度爲MaxLen的字串str,令Len=MaxLen;htm
②把str與D中的詞相匹配;blog
③若匹配成功,則認爲該字串爲詞,指向待切分語料的指針向前移Len個漢字(字節),返回到①;utf-8
④若不成功:若是Len>1,則將Len減2個字節,從待切分語料中取長度爲Len的字串str,返回到②。不然,獲得長度爲2的單字詞,指向待切分語料的指針向前移1個漢字,返回①。
① 掃描方向從左到右,從長到短的順序匹配;
② 原理簡單,程序容易實現,複雜度低。
待分詞文本: content[]=
{「中」,」華」,」民」,」族」,」從」,」此」,」站」,」起」,」來」,」了」,」。」}
詞表: dict[]={「中華」, 「中華民族」 , 「今後」,」站起來」}(1) 從content[1]開始,當掃描到content[2]的時候,發現」中華」已經在詞表dict[]中了。但還不能切分出來,由於咱們不知道後面的詞語能不能組成更長的詞(最大匹配)。
(2) 繼續掃描content[3],發現」中華民」並非dict[]中的詞。可是咱們還不能肯定是否前面找到的」中華」已是最大的詞了。由於」中華民」是dict[2]的前綴。
(3) 掃描content[4],發現」中華民族」是dict[]中的詞。繼續掃描下去:
(4) 當掃描content[5]的時候,發現」中華民族從」並非詞表中的詞,也不是詞的前綴。所以能夠切分出前面最大的詞——」中華民族」。
public static List forwardSeg(String text){ List result=new ArrayList(); while(text.length()>0){ int len=MAX_LENGTH; if(text.length()<MAX_LENGTH){ len=text.length(); } String tryWord=text.substring(0, len); while(!DIC.contains(tryWord)){ if(tryWord.length()==1) break; tryWord=tryWord.substring(0, tryWord.length()-1); } result.add(tryWord+"/"); text=text.substring(tryWord.length()); } return result; }
(1)忽視「詞中有詞」的現象,致使切分錯誤;
(2)最大詞長難以肯定:
①太長:匹配所花時間多,算法時間複雜度高;
②過短:不能切分長度超過它的詞,致使切分正確率下降。
正向最大匹配分詞FMM(Forward Maximum Matching)算法存在設定的最大詞長初始值固定不變的問題,帶來長詞丟失或匹配次數較多的弊端。針對此問題提出了根據中文分詞詞典中的詞條長度動態肯定截取待處理文本長度的思想,改進了FMM算法。與此相配合,設計了一種詞典結構,使之可以有效地支持改進的算法。改進的算法與通常正向最大匹配算法相比大大減小了匹配次數,分析代表中文分詞的速度和效率有了很大提升【參考文獻】
切分出單字串,而後和詞庫進行比對,若是是一個詞就記錄下來, 不然經過增長或者減小一個單字,繼續比較,一直還剩下一個單字則終止。
設MaxLen表示最大詞長,D爲分詞詞典。
(1)將文章分紅句子(經過標點符號來實現);
(2)循環的讀入每個句子S,設句子中的字數爲n;
(3)設置一個最大詞長度,就是咱們要截取的詞的最大長度max;
(4)從句子中取n-max到n的字符串subword,去字典中查找是否有這個詞。若是有就走(5),沒有就走(6);
(5)記住subword,從n-max付值給n,繼續執行(4),直到n=0。
(6)將max-1,再執行(4)。
例子:「我一我的吃飯」。
反向最大匹配方式,最大長度爲5。一我的吃飯
我的吃飯
人吃飯
吃飯 ====>獲得一個詞: 吃飯我一我的
一我的
我的 ====>獲得一個詞: 我的我一
一 ====>獲得一個詞: 一我 ====>獲得一個詞: 我
最後反向最大匹配的結果是:
/我/一/我的/吃飯/
1 public static List reverseSeg(String text){ 2 Stack<String> result=new Stack(); 3 while(text.length()>0){ 4 int len=MAX_LENGTH; 5 if(text.length()<MAX_LENGTH){ 6 len=text.length(); 7 } 8 String tryWord=text.substring(text.length()-len); 9 while(!DIC.contains(tryWord)){ 10 if(tryWord.length()==1){ 11 break; 12 } 13 tryWord=tryWord.substring(1); 14 } 15 result.add(tryWord+"/"); 16 text=text.substring(0,text.length()-tryWord.length()); 17 } 18 int size=result.size(); 19 List list =new ArrayList(size); 20 for(int i=0;i<size;i++){ 21 list.add(result.pop()); 22 } 23 return list; 24 }
切分出單字串,而後和詞庫進行比對,若是是一個詞就記錄下來, 不然經過增長或者減小一個單字,繼續比較,一直還剩下一個單字則終止。
對同一個字符串分別採用MM和RMM兩種方法進行切分處理,若是可以獲得相同的切分結果,則認爲切分紅功,不然認爲有疑點。針對疑點,應採用上下文信息,根據歧義規則庫進行排歧;或者進行人工干預,選取一種正確的切分。
克服了MM方法裏忽視「詞中有詞」的現象。
① 算法複雜度提升。
② 爲了支持正反向匹配算法,詞典設置要更復雜。
③ 對某些句子仍然沒法發現歧義。