
形態素解析とは
文章を構成されている品詞(名詞、動詞、助動詞、副詞、形容詞、接続詞・・・)など最小単位に分離して解析すること。
AIの会話解析や、自動翻訳とか、幅広い分野で応用されています。
私的用途でも、大手検索会社がAPIで提供したりしていて最近は、かなり制度の良い解析が行われるようになりました。
今回は、PHPで1関数で終結してしまう超簡易版を作ります。
超簡易形態素解析をPHPで行う
超簡易形態素解析の内容
超簡易版なので、もちろん辞書を駆使したりとかは、まったくしません。
ただひたすら、文章を半角英数字、全角英数字、カタカナ、かな、漢字に分離して配列に放り込むだけです。
超簡易形態素解析のPHPソース
mb_eregを使用して正規表現で分離します。
テスト用に例文もソースの中に入っています。
<?php
header('Content-Type: text/html; charset=UTF-8');
mb_language("Japanese");
mb_internal_encoding("UTF-8");
mb_http_input("UTF-8");
mb_http_output('UTF-8');
// 語句分離テスト
// 例文
$str = "2018年5月ゴールデンウィークは、何処へ行きますか。現在の気温は、26.5度Tokyo海抜-1.7メートル";
echo "例文=$str<br><br>\n";
// 語句分離処理
$res = goku_sep($str);
// 結果
print_r($res);
//========================================================================
// 超簡易形態素解析(語句分離処理)
//
//
function goku_sep($str)
{
$res = [];
$temp_str = $str;
while(1){
$pos = -1;
$chr_n = 0;
if($n = mb_ereg("[一-龠]+", $temp_str, $match_array)){
// 漢字
$pos = strpos($temp_str, $match_array[0]);
$match = $match_array[0];
$chr_n = $n;
}
if($n = mb_ereg("[ぁ-ん]+", $temp_str, $match_array)){
// かな
$p = strpos($temp_str, $match_array[0]);
if($pos > $p || $pos < 0){
$match = $match_array[0];
$pos = $p; $chr_n = $n;
}
}
if($n = mb_ereg("[ァ-ヴー]+", $temp_str, $match_array)){
// カタカナ
$p = strpos($temp_str, $match_array[0]);
if($pos > $p || $pos < 0){
$match = $match_array[0];
$pos = $p;
$chr_n = $n;
}
}
if($n = mb_ereg("[a-zA-Z0-9.-]+", $temp_str, $match_array)){
// 半角英数字
$p = strpos($temp_str, $match_array[0]);
if($pos > $p || $pos < 0){
$match = $match_array[0];
$pos = $p; $chr_n = $n;
}
}
if($n = mb_ereg("[a-zA-Z0-9]+", $temp_str, $match_array)){
// 全角英数字
$p = strpos($temp_str, $match_array[0]);
if($pos > $p || $pos < 0){
$match = $match_array[0];
$pos = $p;
$chr_n = $n;
}
}
if($chr_n == 0){
// なし
break;
}
$res[] = $match;
$temp_str = substr($temp_str, $pos + $chr_n);
}
return $res;
}
?>
超簡易形態素解析のPHPソース実行結果
上のソースをそのままブラウザで実行すると。

こんな感じ、分かり易くソース変換すると。
例文=2018年5月ゴールデンウィークは、何処へ行きますか。現在の気温は、26.5度Tokyo海抜-1.7メートル<br><br>
Array
(
[0] => 2018
[1] => 年
[2] => 5
[3] => 月
[4] => ゴールデンウィーク
[5] => は
[6] => 何処
[7] => へ
[8] => 行
[9] => きますか
[10] => 現在
[11] => の
[12] => 気温
[13] => は
[14] => 26.5
[15] => 度
[16] => Tokyo
[17] => 海抜
[18] => -1.7
[19] => メートル
)
分離し過ぎとか言う意見もありますが、一応成功ではないでしょうか。
超簡易形態素解析のPHPソース補足
mb_eregの部分を一まとめにすれば、ソースは簡略化できます。
$n = mb_ereg("[一-龠]+|[ぁ-ん]+|[ァ-ヴー]+|[a-zA-Z0-9]+|[a-zA-Z0-9]+", $temp_str, $match_array);
それをあえてしない理由は2つ。
mb_eregを1行にしない理由、その1
PHP 5.2.0 からの
pcre.recursion_limit
pcre.backtrack_limit
への制限で与える文章によっては、処理不能となる恐れがある・・かもしれない!
mb_eregを1行にしない理由、その2
各文字形態で処理を分けた方が、今後のソースの展開に優位。
応用がきく。
などの理由です。
