目次
サンプル・プログラムの実行例
サンプル・プログラム
| NormalizeText.php | サンプル・プログラム本体 |
| pahooNormalizeText.php | テキスト正規化クラス pahooNormalizeText。 テキスト正規化クラスの使い方は「PHPで日本語テキストを正規化」を参照ください。include_pathが通ったディレクトリに配置してください。 |
| special_table.txt | 特殊文字テーブル |
解説:準備
pahooNormalizeText.php
12: class pahooNormalizeText {
13: var $items; //検索結果格納用
14: var $error; //エラーフラグ
15: var $errmsg; //エラーメッセージ
16: var $hits; //検索ヒット件数
17: var $webapi; //直前に呼び出したWebAPI URL
18:
19: //Yahoo! JAPAN Webサービス アプリケーションID
20: //https://developers.google.com/maps/documentation/javascript/get-api-key
21: var $YAHOO_APPLICATION_ID = '**********************************';
22:
23: //gooラボ アプリケーションID
24: //https://labs.goo.ne.jp/apiregister/
25: var $GOOLABS_APPLICATION_ID = '***********************************';
26:
27: //MeCabの実行プログラム;各自の環境に合わせて変更のこと
28: var $MECAB = 'C:\Program Files\MeCab\bin\mecab.exe';
29: //ユーザー辞書
30: var $FILE_UDIC_MECAB = 'C:\Program Files\MeCab\dic\user_wiki.dic';
31: //特殊変換ファイル名
32: var $FILE_SPECIAL = 'special_table.txt';
33:
34: //正規化モード
35: var $OPTION_SPC_TRIM1 = 't'; //行頭・行末の空白文字を除く
36: var $OPTION_SPC_TRIM2 = 'T'; //全角文字と隣り合う空白文字を除く
37: var $OPTION_NUM_HAN = 'n'; //数字を半角に統一
38: var $OPTION_NUM_ZEN = 'N'; //数字を全角に統一
39: var $OPTION_NUM_KAN = 'K'; //数字を漢字に統一
40: var $OPTION_ALP_HAN = 'a'; //英字を半角に統一
41: var $OPTION_ALP_ZEN = 'A'; //英字を全角に統一
42: var $OPTION_YAK_HAN = 'y'; //記号を半角に統一
43: var $OPTION_YAK_ZEN = 'Y'; //記号を全角に統一
44: var $OPTION_KATA_HAN = 'h'; //カタカナを半角に統一
45: var $OPTION_KATA_ZEN = 'H'; //カタカナを全角に統一
46: var $OPTION_SPEC_HAN = 's'; //特殊文字を半角に統一
47: var $OPTION_SPEC_ZEN = 'S'; //特殊文字を全角に統一
48:
49: //年号エスケープ記号(元号・西暦変換させない)
50: var $ESCYEAR = '\\';
「PHPで形態素解析を行う」で紹介した Yahoo! JAPAN Webサービスを利用するには Yahoo! JAPAN Webサービス アプリケーションIDが必要で、その入手方法は「Yahoo!JAPAN デベロッパーネットワーク - WebAPIの登録方法」を参照されたい。
形態素解析として MeCab を使う場合は、実行プログラムのパスを $MECAB に、ユーザー辞書を $FILE_UDIC_MECAB に、作業ファイルを $TMP_FNAME に代入しておく。MeCabユーザー辞書の作り方は「PHPで MeCabのユーザー辞書を作成する」を参照いただきたい。
それから、変換オプションとして変数 $OPTION_ シリーズを用意しておく。
解説:記号の全角⇔半角相互変換
pahooNormalizeText.php
423: /**
424: * 記号の全角⇔半角相互変換
425: * @param string $str 入力テキスト
426: * @param int $mode 変換モード:0=半角から全角, 1=全角から半角
427: * @return string 変換後文字列
428: */
429: function convert_yakumono($str, $mode) {
430: $tbl = array(
431: array(' ', ' '), // 半角スペース⇔全角スペース
432: array('!', '!'),
433: array('\'', '”'),
434: array('#', '#'),
435: array('$', '$'),
436: array('%', '%'),
437: array('&', '&'),
438: array("'", '’'),
439: array('(', '('),
440: array(')', ')'),
441: array('*', '*'),
442: array('+', '+'),
443: array(',', ','),
444: array('-', '-'),
445: array('.', '.'),
446: array('/', '/'),
447: array(':', ':'),
448: array(';', ';'),
449: array('<', '<'),
450: array('=', '='),
451: array('>', '>'),
452: array('?', '?'),
453: array('@', '@'),
454: array('[', '['),
455: array('\\', '¥'),
456: array(']', ']'),
457: array('^', '^'),
458: array('_', '_'),
459: array('`', '`'),
460: array('{', '{'),
461: array('|', '|'),
462: array('}', '}'),
463: array('~', '~'),
464: array('。', '。'),
465: array('「', '「'),
466: array('」', '」'),
467: array('、', '、'),
468: array('・', '・')
469: );
470:
471: foreach ($tbl as $yakumono) {
472: $ch1 = $yakumono[$mode];
473: $ch2 = $yakumono[1 - $mode];
474: $str = str_replace($ch1, $ch2, $str);
475: }
476:
477: return $str;
478: }
仕組みは簡単で、半角記号と全角記号のペアを配列 $tbl に用意しておき、入力文字を1文字1文字比較して、変換するというもの。
この配列を追加・削除すれば、全角⇔半角変換を自在に設定できる。
解説:特殊文字の全角⇔半角相互変換
pahooNormalizeText.php
480: /**
481: * 特殊文字の全角⇔半角相互変換
482: * @param string $sour 入力テキスト
483: * @param int $mode 変換モード:0=半角から全角, 1=全角から半角
484: * @return string 変換後文字列
485: */
486: function convert_special($sour, $mode) {
487: $tbl = array();
488:
489: //特殊文字テーブル読み込み
490: $infp = @fopen($this->FILE_SPECIAL, 'r');
491: if ($infp == FALSE) {
492: $this->error = TRUE;
493: $this->errmsg = $this->FILE_SPECIAL . ' が見つからない.';
494: return FALSE;
495: }
496: $cnt = 0;
497: while (! feof($infp)) {
498: $str = trim(fgets($infp));
499: $arr = preg_split("/\t/ui", $str);
500: if (count($arr) >= 2) {
501: $tbl[$cnt][0] = $arr[0];
502: $tbl[$cnt][1] = $arr[1];
503: $cnt++;
504: }
505: }
506:
507: //変換
508: foreach ($tbl as $special) {
509: $ch1 = $special[$mode];
510: $ch2 = $special[1 - $mode];
511: $sour = str_replace($ch1, $ch2, $sour);
512: }
513:
514: return $sour;
515: }
変換テーブルのファイル名は変数 $FILE_SPECIAL に入れておく。変換テーブルはテキストファイルで、1行が1文字の変換に対応しており、タブの左側に半角文字を、右側に対応する全角文字を記述する。
変換の仕組みは、前述のユーザー関数 convert_yakumono と同じである。
したがって、じつは、左側は半角文字でなくても構わないし、右側は全角文字でなくとも構わない。また、各々が2文字以上になっても大丈夫。
サンプルとして用意した変換テーブルには、"@笑顔@" を "😀" に変換するようなルールを記述してある。
解説:日本語テキストを半角に統一
pahooNormalizeText.php
675: /**
676: * 日本語テキストを半角に統一
677: * @param string $str 漢数字混じりテキスト
678: * @param bool $trim 行頭・行末の空白を除くかどうか
679: * @param int $method 形態素分解方式
680: * 0=MeCab, それ以外=Yahoo!JAPAN 日本語形態素解析Webサービス
681: * @return strin 変換後テキスト
682: */
683: function toHankaku($str, $trim, $method) {
684: //数字パターン
685: $pat_kannum = '/^[^数]*[01234567890123456789○〇一二三四五六七八九十百千万億兆京]+$/ui';
686:
687: //中黒の小数点
688: $str = preg_replace_callback('/([0123456789○〇一二三四五六七八九十百千万億兆京]+)・([01234567890123456789○〇一二三四五六七八九十百千万億兆京]+)/iu',
689: function ($mat) {
690: return $this->kan2num($mat[1], 3) . '.' . $this->kan2num($mat[2], 3);
691: }, $str);
692:
693: //形態素に分解
694: $items = array();
695: if ($method == 0) $this->getParseMeCab($str, $items);
696: else $this->getParseYahoo($str, $items);
697:
698: //変換処理
699: $dest = '';
700: $flag = FALSE;
701: $numstr = '';
702: $i = 0;
703: for ($i = 0; $i < count($items); $i++) {
704: if ($flag == FALSE) {
705: //漢数字の1文字目
706: if ((preg_match($pat_kannum, $items[$i]['surface']) > 0) && (preg_match('/[数|幾]|副詞*/ui', $items[$i]['pos']) > 0)) {
707: $numstr = $items[$i]['surface'];
708: $flag = TRUE;
709: //数字ではない
710: } else {
711: $dest .= $items[$i]['surface'];
712: }
713: } else {
714: //漢数字の2文字目以降
715: if (preg_match($pat_kannum, $items[$i]['surface']) > 0) {
716: $numstr .= $items[$i]['surface'];
717: $flag = TRUE;
718: //数字以外
719: } else {
720: //ここまでの漢数字を半角数字に
721: $dest .= $this->kan2num($numstr, 2) . $items[$i]['surface'];
722: $numstr = '';
723: $flag = FALSE;
724: }
725: }
726: }
727:
728: if ($flag == TRUE) {
729: $dest .= $this->kan2num($numstr, 2);
730: }
731:
732: //英字などの半角変換
733: $dest = $this->convert_special($dest, 1);
734: $dest = mb_convert_kana($dest, 'ask');
735: $dest = $this->convert_yakumono($dest, 1);
736:
737: //行頭・行末空白処理
738: if ($trim) {
739: $arr = preg_split("/\n/iu", $dest);
740: $dest = '';
741: foreach ($arr as $str) {
742: $str = preg_replace('/^[ \t\n\r]+/ui', '', $str); //行頭空白削除
743: $str = preg_replace('/[ \t\n\r]+$/ui', '', $str); //行末空白削除
744: $dest .= $str . "\n";
745: }
746: }
747:
748: return $dest;
749: }
半角に変換するのを担当するのがユーザー関数 toHankaku だ。
まず、中黒の小数点が混じっていたら、組み込み関数 preg_replace_callback を使って、半角数字(小数)に変換する。
次に、テキストを形態素に分解する。
前述の通り、MeCab または Yahoo!JAPAN 日本語形態素解析 Web サービス を利用する。
形態素に分解できたら、漢数字を半角数字に変換していく。
最後に、英字などの半角変換を組み込み関数 mb_convert_kana で、記号はユーザー関数 convert_yakumono で、行頭・行末空白処理を組み込み関数 preg_replace を使って処理する。
解説:日本語テキストを正規化
pahooNormalizeText.php
751: /**
752: * 日本語テキストを正規化する
753: * @param string $str 漢数字混じりテキスト
754: * @param string $option 変換オプション
755: * @param bool $trim 行頭・行末の空白を除くかどうか
756: * @param int $method 形態素分解方式
757: * 0=MeCab, それ以外=Yahoo!JAPAN 日本語形態素解析Webサービス
758: * @return string 変換後テキスト
759: */
760: function normalizeText($str, $option, $trim, $method) {
761: //全角文字と隣り合う空白文字を除く
762: if (strstr($option, $this->OPTION_SPC_TRIM2) != FALSE) {
763: $str = preg_replace('/[ \t]+([\p{Han}\p{Hiragana}\p{Katakana}].)/ui', '\1', $str);
764: }
765:
766: //いったん半角に
767: $dest = $this->toHankaku($str, $trim, $method);
768:
769: //特殊変換:半角→全角変換
770: if (strstr($option, $this->OPTION_SPEC_ZEN) != FALSE) {
771: $dest = $this->convert_special($dest, 0);
772: }
773: //数字:半角→全角変換
774: if (strstr($option, $this->OPTION_NUM_ZEN) != FALSE) {
775: $dest = mb_convert_kana($dest, 'N');
776: //数字:半角→漢数字変換
777: } else if (strstr($option, $this->OPTION_NUM_KAN) != FALSE) {
778: $dest = preg_replace_callback('/[0-9\.]+/ui', array($this, "num2kan_decimal"), $dest);
779: }
780: //英字:半角→全角変換
781: if (strstr($option, $this->OPTION_ALP_ZEN) != FALSE) {
782: $dest = mb_convert_kana($dest, 'R');
783: }
784: //記号:半角→全角変換
785: if (strstr($option, $this->OPTION_YAK_ZEN) != FALSE) {
786: $dest = $this->convert_yakumono($dest, 0);
787: }
788: //カタカナ:半角→全角変換
789: if (strstr($option, $this->OPTION_KATA_ZEN) != FALSE) {
790: $dest = mb_convert_kana($dest, 'VK');
791: }
792: //数字:半角変換
793: if (strstr($option, $this->OPTION_NUM_HAN) != FALSE) {
794: $dest = $this->hanfloat($dest);
795: }
796:
797: return $dest;
798: }
前述のように、まずユーザー関数 toHankaku によってテキスト全体を半角に統一する。
続いて、変換オプションの値に応じて全角や漢数字に変換していく。
参考サイト
- C++ でテキストの正規化:ぱふぅ家のホームページ
- PHPで日本語テキストを正規化(Windowsアプリ版):ぱふぅ家のホームページ
- PHPで漢数字混じりのテキストを半角数字に統一する:ぱふぅ家のホームページ
- PHPで形態素解析を行う:ぱふぅ家のホームページ
- PHPで漢数字を半角数字に変換する(整数版):ぱふぅ家のホームページ

そこで今回は、PHPを使い、全角英字や漢数字混じりの日本語テキストの全角・半角を統一し、算用数字を漢字に変換することもできるようにするプログラムをつくってみることにする。
プログラムは、「PHPで漢数字混じりのテキストを半角数字に統一する」の発展形である。
数字ではなく単語として使われている漢数字「一緒」「三大祭」を認識させるため、「PHPで MeCabのユーザー辞書を作成する」で紹介した MeCab、または「PHPで形態素解析を行う」で紹介した Yahoo!JAPAN 日本語形態素解析 Web サービスを利用し、テキストを形態素に分解してから正規化を行う。
(2021年7月25日)PHP8対応,リファラ・チェック改良