ホームページ php教程 php手册 PHP を使用した中国語単語分割の簡単な実装

PHP を使用した中国語単語分割の簡単な実装

Jun 21, 2016 am 09:05 AM
char gt nbsp this

中文

hehe, 用PHP去做中文分词并不是一个太明智的举动, :p

下面是我根据网上找的一个字典档, 简易实现的一个分词程序.

(注: 字典档是gdbm格式, key是词 value是词频, 约4万个常用词)

完整的程序演示及下载请参见: http://root.twomice.net/my_php4/dict/chinese_segment.php

<?php
//中文分词系统简易实现办法
//切句单位:凡是ascii值<128的字符
//常见双字节符号:《》,。、?“”;:!¥…… %$#@^&*()[]{}|\/"'
//可以考虑加入超常见中文字: 的 和 是 不 了 啊 (不过有特殊字比如 "打的" "郑和" .. :p)

//计算时间
function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
$time_start = getmicrotime();


//词典类
class ch_dictionary {
var $_id;

function ch_dictionary($fname = "") {
if ($fname != "") {
$this->load($fname);
        }
    }

    // 根据文件名载入字典 (gdbm数据档案)
    function load($fname) {
        $this->_id = dba_popen($fname, "r", "gdbm");
        if (!$this->_id) {
            echo "failed to open the dictionary.($fname)<br>\n";
            exit;
        }
    }

    // 根据词语返回频率, 不存在返回-1
    function find($word) {
        $freq = dba_fetch($word, $this->_id);
        if (is_bool($freq)) $freq = -1;
        return $freq;
    }
}

// 分词类: (逆向)
// 先将输入的字串正向切成句子, 然后一句一句的分词, 返回由词组成的数组.
class ch_word_split {
    var $_mb_mark_list;    // 常见切分句子的全角标点
    var $_word_maxlen;    // 单个词最大可能长度(汉字字数)
    var $_dic;        // 词典...
    var $_ignore_mark;    // true or false
   
    function ch_word_split () {
        $this->_mb_mark_list = array(","," ","。","!","?",":","……","、","“","”","《","》","(",")");
        $this->_word_maxlen  = 12;    // 12个汉字
        $this->_dic = NULL;
        $this->_ignore_mark = true;
    }

    // 设定字典
    function set_dic($fname) {
        $this->_dic = new ch_dictionary($fname);
    }

    function set_ignore_mark($set) {
        if (is_bool($set)) $this->_ignore_mark = $set;
    }

    // 将字串切成句子再加以切分成词
    function string_split($str, $func = "") {       
        $ret = array();
       
        if ($func == "" || !function_exists($func)) $func = "";       
       
        $len = strlen($str);
        $qtr = "";

        for ($i = 0; $i < $len; $i++) {
$char = $str[$i];

if (ord($char) < 0xa1) {
// 读取到一个半角字符
if (!empty($qtr)) {
$tmp = $this->_sen_split($qtr);
                    $qtr = "";

                    if ($func != "") call_user_func($func, $tmp);                   
                    else $ret = array_merge($ret, $tmp);                   
                }

                // 如果是单词或数字. 根据 char 将数据读取到 >= 0xa1为止
                if ($this->_is_alnum($char)) {
                    do {
                        if (($i+1) >= $len) break;
                        $char2 = substr($str, $i + 1, 1);
                        if (!$this->_is_alnum($char2)) break;

                        $char .= $char2;
                        $i++;
                    } while (1);

                    if ($func != "") call_user_func($func, array($char));
                    else $ret[] = $char;                   
                }
                elseif ($char == ' ' || $char == "\t") {
                    // nothing.
                    continue;
                }
                elseif (!$this->_ignore_mark) {
                    if ($func != "") call_user_func($func, array($char));
                    else $ret[] = $char;                   
                }
            }
            else {
                // 双字节字符.
                $i++;
                $char .= $str[$i];
               
                if (in_array($char, $this->_mb_mark_list)) {
                    if (!empty($qtr)) {
                        $tmp = $this->_sen_split($qtr);
                        $qtr = "";

                        if ($func != "") call_user_func($func, $tmp);
                        else $ret = array_merge($ret, $tmp);
                    }

                    if (!$this->_ignore_mark) {
                        if ($func != "") call_user_func($func, array($char));
                        else $ret[] = $char;
                    }
                }
                else {
                    $qtr .= $char;
                }
            }
        }
       
        if (strlen($qtr) > 0) {
            $tmp = $this->_sen_split($qtr);

            if ($func != "") call_user_func($func, $tmp);           
            else $ret = array_merge($ret, $tmp);           
        }

        // return value
        if ($func == "") {
            return $ret;
        }
        else {
            return true;
        }
    }

    // 将句子切成词, 逆向
    function _sen_split($sen) {
        $len = strlen($sen) / 2;
        $ret = array();

        for ($i = $len - 1; $i >= 0; $i--) {
            // 如: 这是一个分词程序
           
            // 先取得最后一个字
            $w = substr($sen, $i * 2, 2);

            // 最终的词长
            $wlen = 1;
           
            // 开始逆向匹配到最大长度.
            $lf = 0; // last freq
            for ($j = 1; $j <= $this->_word_maxlen; $j++) {
                $o = $i - $j;
                if ($o < 0) break;
$w2 = substr($sen, $o * 2, ($j + 1) * 2);

$tmp_f = $this->_dic->find($w2);
                //echo "{$i}.{$j}: $w2 (f: $tmp_f)\n";
                if ($tmp_f > $lf) {
                    $lf = $tmp_f;
                    $wlen = $j + 1;
                    $w = $w2;
                }
            }
            // 根据 $wlen 将 $i 偏移了
            $i = $i - $wlen + 1;
            array_push($ret, $w);
        }

        $ret = array_reverse($ret);
        return $ret;
    }

    // 判断字符是不是 字母数字_- [0-9a-z_-]
    function _is_alnum($char) {
        $ord = ord($char);
        if ($ord == 45 || $ord == 95 || ($ord >= 48 && $ord <= 57))
return true;
if (($ord >= 97 && $ord <= 122) || ($ord >= 65 && $ord <= 90))
return true;
return false;
}
}


// 単語分割後のコールバック関数
function call_back($ar) {
foreach ($ar as $tmp) {
echo $tmp . " ";
//flush();
}
}

//例 (入力がない場合は、sample.txt から読み取ります):
$wp = new ch_word_split();
$wp->set_dic("dic.db");

if (!isset($_REQUEST[' testdat'] ) || 空($_REQUEST['testdat'])) {
$data = file_get_contents("sample.txt");
}
else {
$data = & $_REQUEST['testdat'];
}

// Output
echo "<h3>gt;簡単な単語分割のデモンストレーション</h3>n";
echo "<hr>n";
echo "単語分割の結果 (" . strlen($data) . " chars ): <br>n<textareacols=100 rows=10>n";

// 単語の区切り記号(句読点、一般的な単語)を無視して返さないかどうかを設定します
$wp->set_ignore_mark(false);

// 分割を実行します。コールバック関数が設定されていない場合は、単語からなる配列が返されます
$wp->string_split($data, "call_back");

$time_end = getmicrotime();
$time = $time_end - $time_start;

echo "</textarea><br>nこの時間分割にかかる時間: $time 秒 <br>n";
?>
<hr>
<form method=post&gt ;
下のテキスト ボックスにテキストを入力し、送信後に単語の分割効果をテストすることもできます:<br>
<textarea name=testdatcols=100 rows=10></textarea><br>
< ;input type=submit>
</form>
<hr>
添付ファイル: <br>
<li>このプログラムのソースコード: <a href="chinese_segment.phps">chinese_segment.php&lt ;/a> (単純な実装)</li>
<li>必要な辞書: <a href="dic.db">dic.db</a> (gdbm 形式)</li>


添付ファイル:
(簡単な中国語単語の分割のための完全なコードと辞書のダウンロード)
http://php.twomice.net/show_hdr.php?xname=BORRG11&dname=P7SRG11&xpos=19
(簡単な中国語単語の C バージョン)セグメンテーション サービス プログラム (cscwsd) ))
http://php.twomice.net/show_hdr.php?xname=BORRG11&dname=P7SRG11&xpos=40




このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットな記事タグ

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

解決策: 組織では PIN を変更する必要があります。 解決策: 組織では PIN を変更する必要があります。 Oct 04, 2023 pm 05:45 PM

解決策: 組織では PIN を変更する必要があります。

Windows 11 でウィンドウの境界線の設定を調整する方法: 色とサイズを変更する Windows 11 でウィンドウの境界線の設定を調整する方法: 色とサイズを変更する Sep 22, 2023 am 11:37 AM

Windows 11 でウィンドウの境界線の設定を調整する方法: 色とサイズを変更する

Windows 11でタイトルバーの色を変更するにはどうすればよいですか? Windows 11でタイトルバーの色を変更するにはどうすればよいですか? Sep 14, 2023 pm 03:33 PM

Windows 11でタイトルバーの色を変更するにはどうすればよいですか?

Windows 11/10修復におけるOOBELANGUAGEエラーの問題 Windows 11/10修復におけるOOBELANGUAGEエラーの問題 Jul 16, 2023 pm 03:29 PM

Windows 11/10修復におけるOOBELANGUAGEエラーの問題

Windows 11 でタスクバーのサムネイル プレビューを有効または無効にする方法 Windows 11 でタスクバーのサムネイル プレビューを有効または無効にする方法 Sep 15, 2023 pm 03:57 PM

Windows 11 でタスクバーのサムネイル プレビューを有効または無効にする方法

Huawei GT3 ProとGT4の違いは何ですか? Huawei GT3 ProとGT4の違いは何ですか? Dec 29, 2023 pm 02:27 PM

Huawei GT3 ProとGT4の違いは何ですか?

Windows 11 でのディスプレイ スケーリング ガイド Windows 11 でのディスプレイ スケーリング ガイド Sep 19, 2023 pm 06:45 PM

Windows 11 でのディスプレイ スケーリング ガイド

Windows 11で明るさを調整する10の方法 Windows 11で明るさを調整する10の方法 Dec 18, 2023 pm 02:21 PM

Windows 11で明るさを調整する10の方法

See all articles