中文分詞是中文搜尋引擎、文字探勘、自然語言處理的基石。單字切分精度不足,詞級分詞能大幅提升搜尋相關性。本文介紹如何在 PHP 中整合 ICTCLAS (中科院計算所分詞系統) 實現高精度中文分詞。
ICTCLAS (Institute of Computing Technology, Chinese Lexical Analysis System) 是中科院計算所開發的中文分詞系統,特點:
由於 ICTCLAS 為原生二進位程式,PHP 透過 proc_open() 建立管道與其通訊:
<?php
class ChineseTokenizer {
private static $binPath = '';
// 設定 ICTCLAS 執行檔目錄 (不含檔名)
public static function setBinaryPath(string $path): void {
self::$binPath = rtrim($path, '/\\');
}
// 執行分詞指令
private static function execute(string $text): string {
$cmd = self::$binPath . DIRECTORY_SEPARATOR . 'ictclas';
$descriptors = [
0 => ['pipe', 'r'], // stdin
1 => ['pipe', 'w'], // stdout
2 => ['pipe', 'w'] // stderr
];
$proc = proc_open($cmd, $descriptors, $pipes);
if (!is_resource($proc)) {
throw new RuntimeException('無法啟動 ICTCLAS 程序');
}
// ICTCLAS 內部使用 GBK 編碼
$input = iconv('UTF-8', 'GBK//IGNORE', $text);
fwrite($pipes[0], $input);
fclose($pipes[0]);
$output = stream_get_contents($pipes[1]);
fclose($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
fclose($pipes[2]);
$returnCode = proc_close($proc);
if ($returnCode !== 0 && $stderr) {
error_log("ICTCLAS stderr: $stderr");
}
// 輸出轉回 UTF-8
return iconv('GBK', 'UTF-8//IGNORE', trim($output));
}
// 公開介面:分詞並回傳結構化結果
public static function tokenize(string $text): array {
$output = self::execute($text);
$tokens = [];
if ($output) {
// ICTCLAS 輸出格式: "詞/詞性 詞/詞性 ..."
$parts = preg_split('/\s+/', $output);
foreach ($parts as $part) {
if (strpos($part, '/') !== false) {
[$word, $pos] = explode('/', $part, 2);
$tokens[] = [
'word' => $word,
'pos' => $pos,
'pos_name' => self::getPosName($pos)
];
}
}
}
return $tokens;
}
// 簡易模式:僅回傳詞語陣列
public static function segment(string $text): array {
return array_column(self::tokenize($text), 'word');
}
// 詞性代碼對照表 (部分)
private static function getPosName(string $pos): string {
$map = [
'n' => '名詞', 'nr' => '人名', 'ns' => '地名', 'nt' => '機構名',
'v' => '動詞', 'vd' => '動副詞', 'vn' => '名動詞', 'a' => '形容詞',
'd' => '副詞', 'm' => '數詞', 'q' => '量詞', 'r' => '代詞',
'p' => '介詞', 'c' => '連詞', 'u' => '助詞', 'e' => '嘆詞',
'wp' => '標點符號', 'ws' => '外文', 'x' => '非語素字'
];
return $map[$pos] ?? $pos;
}
}
// 設定執行檔路徑 (確保 ictclas 執行檔與詞典在同目錄)
ChineseTokenizer::setBinaryPath(__DIR__ . '/ictclas');
// 使用範例
$text = '台灣積體電路製造公司是全球最大的晶圓代工廠。';
$tokens = ChineseTokenizer::tokenize($text);
echo "<pre>";
print_r($tokens);
echo "</pre>";
/*
輸出範例:
Array
(
[0] => Array ( [word] => 台灣 [pos] => ns [pos_name] => 地名 )
[1] => Array ( [word] => 積體電路 [pos] => n [pos_name] => 名詞 )
[2] => Array ( [word] => 製造 [pos] => v [pos_name] => 動詞 )
[3] => Array ( [word] => 公司 [pos] => n [pos_name] => 名詞 )
[4] => Array ( [word] => 是 [pos] => v [pos_name] => 動詞 )
[5] => Array ( [word] => 全球 [pos] => n [pos_name] => 名詞 )
[6] => Array ( [word] => 最大 [pos] => a [pos_name] => 形容詞 )
[7] => Array ( [word] => 的 [pos] => u [pos_name] => 助詞 )
[8] => Array ( [word] => 晶圓 [pos] => n [pos_name] => 名詞 )
[9] => Array ( [word] => 代工 [pos] => vn [pos_name] => 名動詞 )
[10] => Array ( [word] => 廠 [pos] => n [pos_name] => 名詞 )
[11] => Array ( [word] => 。 [pos] => wp [pos_name] => 標點符號 )
)
*/
?>
# 1. 下載 ICTCLAS Linux 版本
wget https://ictclas.nlpir.org/downloads/ictclas_linux_64bit.tar.gz
tar zxvf ictclas_linux_64bit.tar.gz
cd ictclas
# 2. 確認執行權限
chmod +x ictclas
# 3. 測試執行
echo "測試分詞" | ./ictclas
# 4. 部署至專案目錄
cp -r ictclas /var/www/html/myproject/
頻繁啟動 proc_open 效能較差,高流量建議使用常駐進程:
<?php
class PersistentTokenizer {
private $proc;
private $pipes;
public function __construct(string $binPath) {
$cmd = $binPath . '/ictclas_server'; // 需支援 server 模式的版本
$descriptors = [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w']
];
$this->proc = proc_open($cmd, $descriptors, $this->pipes);
if (!is_resource($this->proc)) {
throw new RuntimeException('無法啟動常駐分詞服務');
}
}
public function tokenize(string $text): array {
$input = iconv('UTF-8', 'GBK//IGNORE', $text) . "\n";
fwrite($this->pipes[0], $input);
$output = fgets($this->pipes[1]); // 讀取單行回應
return $this->parseOutput($output);
}
public function __destruct() {
if (is_resource($this->proc)) {
fclose($this->pipes[0]);
fclose($this->pipes[1]);
fclose($this->pipes[2]);
proc_close($this->proc);
}
}
// parseOutput 同前...
}
?>
若無法部署二進位程式,可考慮純 PHP 實作:
| 專案 | 特點 | Composer 套件 |
|---|---|---|
| jieba-php | 結巴分詞 PHP 移植版,支援自定義詞典 | fukuball/jieba-php |
| SCWS | 簡易中文分詞系統,C 擴充套件效能佳 | pecl/scws |
| PHPAnalysis | 純 PHP 實作,無需編譯擴充套件 | phpanalysis/phpanalysis |