形態素解析とは
文章を構成されている品詞(名詞、動詞、助動詞、副詞、形容詞、接続詞・・・)など最小単位に分離して解析すること。
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
各文字形態で処理を分けた方が、今後のソースの展開に優位。
応用がきく。
などの理由です。