本程式為基於RMM中文分詞思想,編寫的簡易中文分詞,程式中還存在不少漏洞,望大神指點....優化了下亂碼問題
-
/**
- * 基於RMM中文分詞(逆向配對法)
- * @author tangpan
- * @date 2013-10-12
- * @version 1.0.0
- **/
- class SplitWord {
- //public $Tag_dic = array(); //儲存字典分詞
- public $Rec_dic = array(); //儲存重組的分詞
- public $Split_char = ' '; //分隔符號
- public $Source_str = ''; //儲存來源字串
- public $Result_str = ''; //儲存分詞結果字串
- public $limit_lenght = 2;
- public $Dic_maxLen = 28; //字典中詞的最大長度
- public $Dic_minLen = 2; //字典中詞的最大長度
- public $Dic_minLen = 2; // / /字典中詞的最小長度
-
- public function SplitWord() { //初始化對象,並自動執行成員方法
- $this->__construct();
- }
- public function __construct () {
- $dic_path = dirname(__FILE__).'/words.csv'; //預先載入字典以提高分詞速度
- $fp = fopen( $dic_path, 'r' ); //讀取詞庫中的字
- while( $line = fgets( $fp, 256 ) ) {
- $ws = explode(' ', $line); //將字庫中的字分割
- $ws[0] = trim(iconv('utf-8','GBK',$ws[0])); //編碼轉換
- //$this->Tag_dic[$ws[0]] = true; //以字為索引,序號為值
- $this->Rec_dic[strlen($ws[0])][$ws[0]] = true; //以字長度和字分別為二維數組的索引,以n為值,來重組詞庫
- }
- fclose($fp); //關閉詞庫
- }
-
- /**
- * 設定來源字串
- * @param 要分詞的字串
- * /
- public function SetSourceStr( $str ) {
- $str = iconv( 'utf-8', 'GBK', $str ); // 將utf-8編碼字元轉換為GBK編碼
- $ this->Source_str = $this->DealStr( $str ); //初步處理字串
- }
-
- /**
- * 檢查字串
- * @param $str 來源字串
- * @return bool
- */
- public function checkStr( $str ) {
- if ( trim($str) == '' ) return; //若字串為空,直接回傳
- if ( ord( $str[0] ) > 0x80 ) return true; //是中文字元則回傳true
- else return false; //不是中文字元則回傳false
- }
-
-
- /**
- * RMM分詞演算法
- * @param $str 待處理字串
- */
- public function SplitRMM( $str = '' ) {
- if ( trim( $str ) == '' ) return; //若字串為空,則直接回傳
- else $this->SetSourceStr( $str ); //字串不為空時,設定來源字串
- if ( $this->Source_str == ' ' ) return; //當來源字串為空時,直接回傳
- $split_words = explode( ' ', $ this->Source_str ); //以空格來切分字串
- $lenght = count( $split_words ); //計算陣列長度
- for ( $i = $lenght - 1; $i >= 0 ; $i-- ) {
- if ( trim( $split_words[$i] ) == ' ' ) continue; //如果字元為空時,跳過後面的程式碼,直接進入下一次循環
- if ( $this->checkStr( $split_words[$i] ) ) { //檢查字串,如果是中文字元
- if ( strlen( $split_words[$i] ) >= $this->limit_lenght ) { //字串長度大於限制大小時
- //對字串進行逆向比對
- $this->Result_str = $this->pregRmmSplit( $split_words[$i] ).$this->Split_char.$ this->Result_str;
- }
- } else {
- $this->Result_str = $split_words[$i].$this->Split_char.$this->Result_str;
- }
- }
- $this->clear( $split_words ); //釋放記憶體
- return iconv('GBK', 'utf-8', $this->Result_str);
- }
-
- /**
- * 對中文字串進行逆向匹配方式分解
- * @param $str 字串
- * @return $retStr 分詞完成的字串
- */
- public function pregRmmSplit( $str ) {
- if ( $str == ' ' ) return;
- $splen = strlen( $str );
- $
- $splen = strlen( $str );
- $
- $splen = strlen( $str );
- $ $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 {
- $w = trim( substr( $str, 0, $this->Dic_minLen 1 ) ); //截取前四個字元
- if ( $this->IsWord( $w ) ) { / /判斷字典中是否存在該字元
- $Split_Result[] = $w; //存在,則寫入陣列儲存
- } else {
- $Split_Result[] = substr( $str, 2, 2 ); //逆向儲存
- $Split_Result[] = substr( $str, 0, 2 );
- }
- }
- $j = -1; //關閉迴圈;
- break ;
- }
- if ( $j >= $this->Dic_maxLen ) $max_len = $this->Dic_maxLen; //當字元長度大於字典最大詞的長度時,賦值最大限制長度
- else $max_len = $j;
- for ( $k = $max_len; $k >= 0; $k = $k - 2 ) { //一次跳動為一個中文字元
- $w = trim( substr( $str, $j - $k, $k 1 ) );
- if ( $this->IsWord( $w ) ) {
- $Split_Result[] = $w; //存該字
- $j = $j - $k - 1; //位置移動到已匹配的字符的位置
- break; //分詞成功即跳出當前循環,進入下一循環
- }
- }
- }
- $retStr = $this->resetWord( $Split_Result ); //重組字串,並回傳處理好的字串
- $this->clear( $Split_Result ); //釋放記憶體
- return $retStr;
- }
-
- /**
- * 重新辨識並組合分詞
- * @param $Split_Result 重組目標字串
- * @return $ret_Str 重組字串
- */
- public function resetWord( $Split_Result ) {
- if ( trim( $Split_Result==[0] ) == ' ' ) return;
- $Len = count( $Split_Result ) - 1;
- $ret_Str = '';
- $spc = $this->Split_char;
- for ( $i = $Len; $i >= 0; $i-- ) {
- if ( trim( $Split_Result[$i] ) != '' ) {
- $Split_Result[$i] = iconv( 'GBK', 'utf -8', $Split_Result[$i] );
- $ret_Str .= $spc.$Split_Result[$i].' ';
- }
- }
- //$ret_Str = preg_replace( '/^'.$spc.'/','、',$ret_Str);
- $ret_Str = iconv('utf-8','GBK',$ret_Str);
- return $ret_Str;
- }
-
- /**
- * 檢查字典中是否存在某個字
- * @param $okWord 檢查的字
- * @return bool;
- */
- public function IsWord( $okWord ) {
- $len = strlen( $okWord );
- if ( $len > $this ->Dic_maxLen 1 ) return false;
- else { //根據二維數組索引匹配,是否存在該詞
- return isset($this->Rec_dic[$len][$okWord]);
- }
-
- }
-
- /**
- * 初步處理字串(以空格來替換特殊字元)
- * @param $str 要處理的來源字串
- * @return $okStr 傳回預處理好的字串
- */
- public function DealStr( $str ) {
- $spc = $this->Split_char; //拷貝分隔符
- $slen = strlen( $str ); //計算字元的長度
- if ( $slen == 0 ) return; //如果字元長度為0,直接回傳
- $okstr = ''; //初始化變數
- $prechar = 0; //字元判斷變數(0-空白,1-英文,2-中文,3-符號)
- for ( $i = 0; $i $str_ord = ord( $str[$i] );
- if ( $str_ord if ( $str_ord if ( $str[$i] != 'r' && $str[$i] != 'n' )
- $okstr .= $spc;
- $prechar = 0 ;
- continue;
- } else if ( ereg('[@.%#:^&_-]',$str[$i]) ) { //如果關鍵字的字元是數字或英文或特殊字元
- if ( $prechar == 0 ) { //當字元為空白符時
- $okstr .= $str[$i];
- $prechar = 3;
- } else {
- $okstr .= $spc.$str[$i]; //字元不為空格符時,在字元前串上空白符
- $prechar = 3;
- }
- } else if ( ereg('[0-9a-zA-Z]', $str[$i]) ) { //分割英文數字組合
- if ( (ereg('[0-9]',$str[$ i-1]) && ereg('[a-zA-Z]',$str[$i]))
- || (ereg('[a-zA-Z]',$str[$i- 1]) && ereg('[0-9]',$str[$i])) ) {
- $okstr .= $spc.$str[$i];
- } else {
- $okstr .= $str[$i];
- }
- }
- }else { //如果關鍵字的第二個字元是漢字
- if ( $prechar != 0 && $prechar != 2 ) //如果上一個字元為非中文和非空格,則加一個空格
- $okstr .= $spc;
- if ( isset( $str[$i 1] ) ) { //如果是中文字元
- $c = $str[$i].$str[$i 1 ]; //將兩個字串在一起,構成一個中文字
- $n = hexdec( bin2hex( $c ) ); //將ascii碼轉換成16進制,再轉換為10進位
- if ( $n > 0xA13F && $n if ( $prechar != 0 ) $okstr .= $spc; //將中文標點替換為空
- //else $okstr .= $spc; //若前一個字元為空,則直接串上
- $prechar = 3;
- } else { //若不是中文標點
- $okstr .= $c;
- $prechar = 2;
- }
- $i ; // $i 再加1 ,即使一次移動為一個中文字元
- }
- }
- }
- return $okstr;
- }
-
- /**
- * 釋放記憶體
- * @param $data 暫存資料
- */
- public function clear( $data ) {
- unset( $data ); //刪除暫存資料
- }
- }
- ?>
複製程式碼
|