RMM 単語分割アルゴリズム クラス
- //RMM 単語分割アルゴリズム
- class SplitWord{
- var $TagDic = Array();
- var $RankDic = Array();
- var $SourceStr = '';
- var $ResultStr = '';
- var $ SplitChar = ' '; //Separator
- var $SplitLen = 4; // 予約された単語の長さ
- var $MaxLen = 7; // ここの値はバイト配列の最大インデックスですvar $MinLen = 3; //最小の中国語文字、ここでの値はバイト配列の最大インデックスです
-
- function SplitWord(){
- $this->__construct();
- }
-
- function __construct(){
- //高度な単語分割、単語分割速度を向上させるために辞書をプリロードします
- $dicfile = dirname(__FILE__)."/ppldic.csv"; // 単語を読み取ります辞書
- while ($line = fgets($fp,256)){
- $ws =explode(' ',$line) // 語彙内の単語を分割します
- $this->TagDic[$ws[0 ] ] = $ws[1];
- $this->RankDic[strlen($ws[0])][$ws[0]] = $ws[2];
- }
- fclose($fp); / 辞書ファイルを閉じる
- }
-
- // リソースを抽出する
- function Clear(){
- @fclose($this->QuickDic);
- }
-
- // ソース文字列を設定する
- function SetSource($str){
- $this->SourceStr = $this->UpdateStr($str);
- $this->ResultStr = "";
- }
-
- //文字列が中国語に存在しないかをチェック
- function NotGBK($str) )
- {
- if($str=="") return "";
- if( ord($str[0])>0x80 ) return false;
- else return true;
- }
-
- //RMM 単語分割アルゴリズム
- 関数 SplitRMM ($str=""){
- if($str!="") $this->SetSource($str);
- if($this->SourceStr=="") return "";
- $this ->SourceStr = $this->UpdateStr($this->SourceStr);
- $spwords =explode(" ",$this->SourceStr);
- $spLen = count($spwords);
- $spc = $this->SplitChar;
- for($i=($spLen-1);$i>=0;$i--){
- if($spwords[$i]=="")続行;
- if($this->NotGBK($spwords[$i])){
- if(preg_match("/[^0-9.+-]/",$spwords[$i]))
- { $this- >ResultStr = $spwords[$i].$spc.$this->ResultStr; }
- else
- {
- $nextword = "";
- @$nextword = substr($this->ResultStr, 0,strpos ($this->ResultStr,""));
- }
- }
- else
- {
- $c = $spwords[$i][0].$spwords[$i][1];
- $ n = hexdec (bin2hex($c));
- if(strlen($spwords[$i]) <= $this->SplitLen)
- {
- }
- else
- {
- $this->ResultStr = $ this-> ;RunRMM($spwords[$i]).$spc.$this->ResultStr;
- }
- }
- }
- return $this->ResultStr;
- }
- //すべての中国語の逆一致メソッド文字列を分解する
- function RunRMM($str){
- $spc = $this->SplitChar;
- $spLen = strlen($str);
- $rsStr = "";
- $okWord = "";
- $tmpWord = " " ;
- $WordArray = Array();
- //辞書の逆引きマッチング
- for($i=($spLen-1);$i>=0;){
- //最小の単語に到達したとき
- if( $i<=$this->MinLen){
- if($i==1){
- $WordArray[] = substr($str,0,2);
- }else
- {
- $w = substr($ str,0,$this->MinLen+1);
- if($this->IsWord($w)){
- $WordArray[] = $w;
- }else{
- $WordArray[] = substr( $str,2,2);
- $WordArray[] = substr($str,0,2);
- }
- }
- $i = -1; Break;
- }
- //最小単語より上の状況を分析する
- if($i>=$this->MaxLen) $maxPos = $this->MaxLen;
- else $maxPos = $i;
- $isMatch = false;
- for($j=$maxPos;$j> = 0;$j=$j-2){
- $w = substr($str,$i-$j,$j+1);
- if($this->IsWord($w)){
- $ WordArray [] = $w;
- $i = $i-$j-1;
- $isMatch = true;
- Break;
- }
- }
- }
- $rsStr = $this->otherword($WordArray);
- return $rsStr;
- }
-
- function otherword($WordArray){
- $wlen = count($WordArray)-1; //配列の要素数を計算します
- $rsStr = "" //変数を初期化します
- $spc; = $this->SplitChar;
- for($i=$wlen;$i>=0;$i--)
- {
- $rsStr .= $spc.$WordArray[$i].","; / 配列をカンマで分割します
- }
- //この段落の単語分割結果を返します
- $rsStr = preg_replace("/^".$spc."/",",",$rsStr);
- return $rsStr;
- }
-
- //特定の単語が辞書に存在するかどうかを判断します
- function IsWord($okWord){
- $slen = strlen($okWord);
- if($slen > $this->MaxLen) return false;
- else return isset($this->RankDic[$slen][$okWord]);
- }
-
- //文字列の整理(句読点、中国語と英語の混在などの事前処理)
- function UpdateStr($str) {
- $ spc = $this->SplitChar;
- $slen = strlen($str);
- if($slen==0) return '';
- $okstr = '';
- $prechar = 0; // 0-空白 1-英語 2-中国語 3-記号
- for($i=0;$i<$slen;$i++){
- if(ord($str[$i]) <0x81){
- //英語記号の空白
- if(ord($str[$i]) < 33){
- if($prechar!=0&&$str[$i]!="r"&&$str[$i]!=" n") $okstr .= $spc;
- $prechar=0;
- continue;
- }else if(preg_match("/[^0-9a-zA-Z@.%#:\&_-]/",$ str[$ i])){
- if($prechar==0){ $okstr .= $str[$i];}
- else{ $okstr .= $spc.$str[$i ]; $ prechar=3;}
- }else{
- if($prechar==2||$prechar==3)
- { $okstr .= $spc.$str[$i];}
- else
- {
- if(preg_match("/@#%:/",$str[$i])){ $okstr .= $str[$i]; }
- else { $okstr . = $str [$i]; $prechar=1; }
- }
- }
- }
- else{
- //前の文字が中国語以外でスペースでない場合は、スペースを追加します
- if($prechar!=0 && $prechar! =2) $okstr .= $spc;
- //漢字の場合
- if(isset($str[$i+1])){
- $c = $str[$i].$str[ $i+1 ];
-
- $n = hexdec(bin2hex($c));
- if($n<0xA13F && $n > 0xAA40){
- if($prechar!=0) $okstr .= $spc .$c;
- else $okstr .= $c;
- $prechar = 3;
- }
- else{
- $okstr .= $c;
- $prechar = 2;
- }
- $i++;
- }
- }
- }
- return $okstr ;
- }
- }
-
- // Call
- $split=new SplitWord();
-
- echo $split->SplitRMM("php search technology");
-
- // ppldic の形式に注意してください.csv 辞書は word+Space+Number+n
-
コードをコピー
|