このプログラムは、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 = ' '; //Separator
- public $Source_str = ''; //ストレージソース文字列
- public $Result_str = ''; public $Dic_maxLen = 28; //辞書内の単語の最大長
- public $Dic_minLen = 2 //辞書内の単語の最小長
- public function SplitWord() { //オブジェクトを初期化し、メンバーを自動的に実行しますMethods
- $ 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;単語の長さと単語 それぞれ 2 次元配列のインデックスであり、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 (rim( $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 (rim( $split_words[$i] ) == ' ' ) continue;文字が空の場合は、次のコードをスキップして次の 1 つのループに直接進みます
- if ( $this->checkStr( $split_words[$i] ) ) { //文字列が漢字かどうかを確認します
- if ( strlen( $split_words[$i] ) >= $this-> ;limit_length ) { //文字列の長さが制限サイズより大きい場合
- //文字列を逆引き
- $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 string
- * @return $retStr 単語分割で完成した文字列
- */
- public function pregRmmSplit( $str ) {
- if ( $str == ' ' ) return;
- $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 ) ); //最初の 4 文字を切り捨てます
- 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; //文字の長さが辞書内の最大の単語の長さを超える場合、最大制限長を割り当てます
- それ以外の場合 $max_len = $j;
- for ( $k = $max_len; $k >= 0; $k = $k - 2 ) { //1 つのジャンプは 1 つの漢字です
- $w = トリム( 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 文字列を再構築します
- */
- function restartWord( $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 < $slen; $i++ ) {
- $str_ord = ord( $str[$i] );
- if ( $str_ord < 0x81 ) { //英字の場合
- if ( $str_ord < 33 ) { // 英語の空白記号
- 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 { //キーワードの 2 番目の文字が漢字の場合
- if ( $prechar != 0 && $prechar != 2 ) // 前の文字が中国語以外でスペース以外の場合は、スペースを追加します
- $ okstr . = $spc;
- if ( isset( $str[$i+1] ) ) { //漢字の場合
- $c = $str[$i].$str[$i+1]; //2 つの文字列をまとめて漢字に変換します
- $n = hexdec( bin2hex( $c ) ) //ASCII コードを 16 進数に変換し、次に 10 進数に変換します
- if ( $n > 0xA13F && $ n < ; 0xAA40 ) { //中国語の句読点の場合
- if ( $prechar != 0 ) $okstr .= $spc; //中国語の句読点を空の記号に置き換えます
- //else $okstr .= $spc; ; // 前の文字が空の場合は、直接文字列化します
- $prechar = 3;
- } else { // 中国語の句読点でない場合
- $okstr .= $c;
- $prechar = 2;
- }
- $i++ ; // $ i に 1 を加えます (一度に 1 文字ずつ移動する場合も同様) }
- }
- }
- return $okstr;
- }
-
- /**
- * メモリを解放します
- * @param $data 一時データ
- */
- public function clear( $data ) {
- unset( $data ) ; //一時データを削除
- }
- }
- ?>
-
コードをコピー
|