首頁 > 後端開發 > php教程 > 基於RMM的簡易中文分詞

基於RMM的簡易中文分詞

WBOY
發布: 2016-07-25 08:49:34
原創
1198 人瀏覽過
本程式為基於​​RMM中文分詞思想,編寫的簡易中文分詞,程式中還存在不少漏洞,望大神指點....優化了下亂碼問題
  1. /**
  2. * 基於RMM中文分詞(逆向配對法)
  3. * @author tangpan
  4. * @date 2013-10-12
  5. * @version 1.0.0
  6. **/
  7. class SplitWord {
  8. //public $Tag_dic = array(); //儲存字典分詞
  9. public $Rec_dic = array(); //儲存重組的分詞
  10. public $Split_char = ' '; //分隔符號
  11. public $Source_str = ''; //儲存來源字串
  12. public $Result_str = ''; //儲存分詞結果字串
  13. public $limit_lenght = 2;
  14. public $Dic_maxLen = 28; //字典中詞的最大長度
  15. public $Dic_minLen = 2; //字典中詞的最大長度
  16. public $Dic_minLen = 2; // / /字典中詞的最小長度
  17. public function SplitWord() { //初始化對象,並自動執行成員方法
  18. $this->__construct();
  19. }
  20. public function __construct () {
  21. $dic_path = dirname(__FILE__).'/words.csv'; //預先載入字典以提高分詞速度
  22. $fp = fopen( $dic_path, 'r' ); //讀取詞庫中的字
  23. while( $line = fgets( $fp, 256 ) ) {
  24. $ws = explode(' ', $line); //將字庫中的字分割
  25. $ws[0] = trim(iconv('utf-8','GBK',$ws[0])); //編碼轉換
  26. //$this->Tag_dic[$ws[0]] = true; //以字為索引,序號為值
  27. $this->Rec_dic[strlen($ws[0])][$ws[0]] = true; //以字長度和字分別為二維數組的索引,以n為值,來重組詞庫
  28. }
  29. fclose($fp); //關閉詞庫
  30. }
  31. /**
  32. * 設定來源字串
  33. * @param 要分詞的字串
  34. * /
  35. public function SetSourceStr( $str ) {
  36. $str = iconv( 'utf-8', 'GBK', $str ); // 將utf-8編碼字元轉換為GBK編碼
  37. $ this->Source_str = $this->DealStr( $str ); //初步處理字串
  38. }
  39. /**
  40. * 檢查字串
  41. * @param $str 來源字串
  42. * @return bool
  43. */
  44. public function checkStr( $str ) {
  45. if ( trim($str) == '' ) return; //若字串為空,直接回傳
  46. if ( ord( $str[0] ) > 0x80 ) return true; //是中文字元則回傳true
  47. else return false; //不是中文字元則回傳false
  48. }
  49. /**
  50. * RMM分詞演算法
  51. * @param $str 待處理字串
  52. */
  53. public function SplitRMM( $str = '' ) {
  54. if ( trim( $str ) == '' ) return; //若字串為空,則直接回傳
  55. else $this->SetSourceStr( $str ); //字串不為空時,設定來源字串
  56. if ( $this->Source_str == ' ' ) return; //當來源字串為空時,直接回傳
  57. $split_words = explode( ' ', $ this->Source_str ); //以空格來切分字串
  58. $lenght = count( $split_words ); //計算陣列長度
  59. for ( $i = $lenght - 1; $i >= 0 ; $i-- ) {
  60. if ( trim( $split_words[$i] ) == ' ' ) continue; //如果字元為空時,跳過後面的程式碼,直接進入下一次循環
  61. if ( $this->checkStr( $split_words[$i] ) ) { //檢查字串,如果是中文字元
  62. if ( strlen( $split_words[$i] ) >= $this->limit_lenght ) { //字串長度大於限制大小時
  63. //對字串進行逆向比對
  64. $this->Result_str = $this->pregRmmSplit( $split_words[$i] ).$this->Split_char.$ this->Result_str;
  65. }
  66. } else {
  67. $this->Result_str = $split_words[$i].$this->Split_char.$this->Result_str;
  68. }
  69. }
  70. $this->clear( $split_words ); //釋放記憶體
  71. return iconv('GBK', 'utf-8', $this->Result_str);
  72. }
  73. /**
  74. * 對中文字串進行逆向匹配方式分解
  75. * @param $str 字串
  76. * @return $retStr 分詞完成的字串
  77. */
  78. public function pregRmmSplit( $str ) {
  79. if ( $str == ' ' ) return;
  80. $splen = strlen( $str );
  81. $
  82. $splen = strlen( $str );
  83. $
  84. $splen = strlen( $str );
  85. $ $splen = strlen( $str ); $ $splen = strlen( $str ); $ Split_Result = array(); for ( $j = $splen - 1; $j >= 0; $j--) { //逆向匹配字元 if ( $splen Dic_minLen ) { //當字元長度大於字典中最小字元長度時 if ( $j == 1 ) { //當長度為1 時 $Split_Result[] = substr( $str, 0, 2 ) ; }else {
  86. $w = trim( substr( $str, 0, $this->Dic_minLen 1 ) ); //截取前四個字元
  87. if ( $this->IsWord( $w ) ) { / /判斷字典中是否存在該字元
  88. $Split_Result[] = $w; //存在,則寫入陣列儲存
  89. } else {
  90. $Split_Result[] = substr( $str, 2, 2 ); //逆向儲存
  91. $Split_Result[] = substr( $str, 0, 2 );
  92. }
  93. }
  94. $j = -1; //關閉迴圈;
  95. break ;
  96. }
  97. if ( $j >= $this->Dic_maxLen ) $max_len = $this->Dic_maxLen; //當字元長度大於字典最大詞的長度時,賦值最大限制長度
  98. else $max_len = $j;
  99. for ( $k = $max_len; $k >= 0; $k = $k - 2 ) { //一次跳動為一個中文字元
  100. $w = trim( substr( $str, $j - $k, $k 1 ) );
  101. if ( $this->IsWord( $w ) ) {
  102. $Split_Result[] = $w; //存該字
  103. $j = $j - $k - 1; //位置移動到已匹配的字符的位置
  104. break; //分詞成功即跳出當前循環,進入下一循環
  105. }
  106. }
  107. }
  108. $retStr = $this->resetWord( $Split_Result ); //重組字串,並回傳處理好的字串
  109. $this->clear( $Split_Result ); //釋放記憶體
  110. return $retStr;
  111. }
  112. /**
  113. * 重新辨識並組合分詞
  114. * @param $Split_Result 重組目標字串
  115. * @return $ret_Str 重組字串
  116. */
  117. public function resetWord( $Split_Result ) {
  118. if ( trim( $Split_Result==[0] ) == ' ' ) return;
  119. $Len = count( $Split_Result ) - 1;
  120. $ret_Str = '';
  121. $spc = $this->Split_char;
  122. for ( $i = $Len; $i >= 0; $i-- ) {
  123. if ( trim( $Split_Result[$i] ) != '' ) {
  124. $Split_Result[$i] = iconv( 'GBK', 'utf -8', $Split_Result[$i] );
  125. $ret_Str .= $spc.$Split_Result[$i].' ';
  126. }
  127. }
  128. //$ret_Str = preg_replace( '/^'.$spc.'/','、',$ret_Str);
  129. $ret_Str = iconv('utf-8','GBK',$ret_Str);
  130. return $ret_Str;
  131. }
  132. /**
  133. * 檢查字典中是否存在某個字
  134. * @param $okWord 檢查的字
  135. * @return bool;
  136. */
  137. public function IsWord( $okWord ) {
  138. $len = strlen( $okWord );
  139. if ( $len > $this ->Dic_maxLen 1 ) return false;
  140. else { //根據二維數組索引匹配,是否存在該詞
  141. return isset($this->Rec_dic[$len][$okWord]);
  142. }
  143. }
  144. /**
  145. * 初步處理字串(以空格來替換特殊字元)
  146. * @param $str 要處理的來源字串
  147. * @return $okStr 傳回預處理好的字串
  148. */
  149. public function DealStr( $str ) {
  150. $spc = $this->Split_char; //拷貝分隔符
  151. $slen = strlen( $str ); //計算字元的長度
  152. if ( $slen == 0 ) return; //如果字元長度為0,直接回傳
  153. $okstr = ''; //初始化變數
  154. $prechar = 0; //字元判斷變數(0-空白,1-英文,2-中文,3-符號)
  155. for ( $i = 0; $i $str_ord = ord( $str[$i] );
  156. if ( $str_ord if ( $str_ord if ( $str[$i] != 'r' && $str[$i] != 'n' )
  157. $okstr .= $spc;
  158. $prechar = 0 ;
  159. continue;
  160. } else if ( ereg('[@.%#:^&_-]',$str[$i]) ) { //如果關鍵字的字元是數字或英文或特殊字元
  161. if ( $prechar == 0 ) { //當字元為空白符時
  162. $okstr .= $str[$i];
  163. $prechar = 3;
  164. } else {
  165. $okstr .= $spc.$str[$i]; //字元不為空格符時,在字元前串上空白符
  166. $prechar = 3;
  167. }
  168. } else if ( ereg('[0-9a-zA-Z]', $str[$i]) ) { //分割英文數字組合
  169. if ( (ereg('[0-9]',$str[$ i-1]) && ereg('[a-zA-Z]',$str[$i]))
  170. || (ereg('[a-zA-Z]',$str[$i- 1]) && ereg('[0-9]',$str[$i])) ) {
  171. $okstr .= $spc.$str[$i];
  172. } else {
  173. $okstr .= $str[$i];
  174. }
  175. }
  176. }else { //如果關鍵字的第二個字元是漢字
  177. if ( $prechar != 0 && $prechar != 2 ) //如果上一個字元為非中文和非空格,則加一個空格
  178. $okstr .= $spc;
  179. if ( isset( $str[$i 1] ) ) { //如果是中文字元
  180. $c = $str[$i].$str[$i 1 ]; //將兩個字串在一起,構成一個中文字
  181. $n = hexdec( bin2hex( $c ) ); //將ascii碼轉換成16進制,再轉換為10進位
  182. if ( $n > 0xA13F && $n if ( $prechar != 0 ) $okstr .= $spc; //將中文標點替換為空
  183. //else $okstr .= $spc; //若前一個字元為空,則直接串上
  184. $prechar = 3;
  185. } else { //若不是中文標點
  186. $okstr .= $c;
  187. $prechar = 2;
  188. }
  189. $i ; // $i 再加1 ,即使一次移動為一個中文字元
  190. }
  191. }
  192. }
  193. return $okstr;
  194. }
  195. /**
  196. * 釋放記憶體
  197. * @param $data 暫存資料
  198. */
  199. public function clear( $data ) {
  200. unset( $data ); //刪除暫存資料
  201. }
  202. }
  203. ?>
複製程式碼
基於RMM的簡易中文分詞


來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板