サンプル・プログラムの実行例

サンプル・プログラム
解説:準備
44: //Yahoo! JAPAN Webサービス アプリケーションID
45: //取得方法 https://www.pahoo.org/e-soul/webtech/php06/php06-01-02.shtm#Yahoo
46: define('APPLICATION_ID', '*******************************************');
取得したIDは定数 APPLICATION_ID に格納する。
サンプル・プログラムの流れ

解説:変換処理
441: /**
442: * 漢数字を半角数字に変換する
443: * @param string $kanji 漢数字
444: * @param int $mode 出力書式/1=3桁カンマ区切り,2=漢字混じり, それ以外=ベタ打ち
445: * @return string 半角数字
446: */
447: function kan2num($kanji, $mode) {
448: //半角数字が混在していたら何もしない
449: if (preg_match('/[0-9]+/ui', $kanji) > 0) return $kanji;
450:
451: //全角=半角対応表
452: $kan_num = array(
453: '0' => 0, '〇' => 0,
454: '1' => 1, '一' => 1, '壱' => 1,
455: '2' => 2, '二' => 2, '弐' => 2,
456: '3' => 3, '三' => 3, '参' => 3,
457: '4' => 4, '四' => 4,
458: '5' => 5, '五' => 5,
459: '6' => 6, '六' => 6,
460: '7' => 7, '七' => 7,
461: '8' => 8, '八' => 8,
462: '9' => 9, '九' => 9
463: );
464: //位取り
465: $kan_deci_sub = array('十' => 10, '百' => 100, '千' => 1000);
466: $kan_deci = array('万' => 10000, '億' => 100000000, '兆' => 1000000000000, '京' => 10000000000000000);
467:
468: //右側から解釈していく
469: $ll = mb_strlen($kanji);
470: $a = '';
471: $deci = 1;
472: $deci_sub = 1;
473: $m = 0;
474: $n = 0;
475: for ($pos = $ll - 1; $pos >= 0; $pos--) {
476: $c = mb_substr($kanji, $pos, 1);
477: if (isset($kan_num[$c])) {
478: $a = $kan_num[$c] . $a;
479: } else if (isset($kan_deci_sub[$c])) {
480: if ($a != '') $m = $m + $a * $deci_sub;
481: else if ($deci_sub != 1) $m = $m + $deci_sub;
482: $a = '';
483: $deci_sub = $kan_deci_sub[$c];
484: } else if (isset($kan_deci[$c])) {
485: if ($a != '') $m = $m + $a * $deci_sub;
486: else if ($deci_sub != 1) $m = $m + $deci_sub;
487: $n = $m * $deci + $n;
488: $m = 0;
489: $a = '';
490: $deci_sub = 1;
491: $deci = $kan_deci[$c];
492: }
493: }
494:
495: $ss = '';
496: if (preg_match("/^(0+)/", $a, $regs) != FALSE) $ss = $regs[1];
497: if ($a != '') $m = $m + $a * $deci_sub;
498: else if ($deci_sub != 1) $m = $m + $deci_sub;
499: $n = $m * $deci + $n;
500:
501: //出力書式に変換
502: if ($ss == '') {
503: $dest = $n;
504: switch ($mode) {
505: case 1:
506: $dest = number_format($n);
507: break;
508: case 2:
509: $dest = int2kanji($n);
510: break;
511: default:
512: }
513: } else if ($n == 0) {
514: $dest = $ss;
515: } else {
516: $dest = $ss . $n;
517: }
518:
519: return $dest;
520: }
522: /**
523: * 漢数字混じりのテキストを半角数字混じりテキストに変換する
524: * @param string $str 漢数字混じりテキスト
525: * @param string $func 形態素解析に使う関数
526: * @return strin 変換後テキスト
527: */
528: function convert_kan2num($str, $func) {
529: //数字パターン
530: $pat_kannum = '/^[01234567890123456789〇一二三四五六七八九十百千万億兆京]+$/ui';
531:
532: //中黒の小数点
533: $str = preg_replace_callback('/([0123456789〇一二三四五六七八九十百千万億兆京]+)・([01234567890123456789〇一二三四五六七八九十百千万億兆京]+)/iu',
534: function ($mat) {
535: return kan2num($mat[1], 3) . '.' . kan2num($mat[2], 3);
536: }, $str);
537:
538: //形態素に分解:Yahoo!JAPAN 日本語形態素解析Webサービス
539: $items = array();
540: $func($str, $items);
541:
542: //結果を1単語ずつ取得
543: $dest = '';
544: $flag = FALSE;
545: $numstr = '';
546: $i = 0;
547: for ($i = 0; $i < count($items); $i++) {
548: if ($flag == FALSE) {
549: if (preg_match($pat_kannum, $items[$i]['surface']) > 0) {
550: $numstr = $items[$i]['surface'];
551: $flag = TRUE;
552: } else {
553: $dest .= $items[$i]['surface'];
554: }
555: } else {
556: if (preg_match($pat_kannum, $items[$i]['surface']) > 0) {
557: $numstr .= $items[$i]['surface'];
558: $flag = TRUE;
559: } else if ($items[$i]['pos'] == '名詞') {
560: $dest .= $numstr . $items[$i]['surface'];
561: $numstr = '';
562: $flag = FALSE;
563: } else {
564: $dest .= kan2num($numstr, 2) . $items[$i]['surface'];
565: $numstr = '';
566: $flag = FALSE;
567: }
568: }
569: }
570: if ($flag == TRUE) {
571: $dest .= kan2num($numstr, 2);
572: }
573:
574: return $dest;
575: }

まず、テキストを日本語形態素解析Webサービスに渡し、形態素に分解する。後述するように、形態素の品詞を取得することが重要であるためだ。このWebAPIについては「PHPで形態素解析を行う」で紹介しているので、そちらを参考にしてほしい。

分解された形態素を結合して変数 $dest に代入していく過程で、漢数字を半角数字に変換する。
まず、その形態素が漢数字なら、漢数字をバッファリングする変数 $numstr に代入し、$flag をTRUEにする。$flag は前の形態素が漢数字かどうかを保持することになる。
その形態素が漢数字でなければ、半角数字変換後のテキストを格納する変数 $dest に追加する。

前の形態素が漢数字でなく、その形態素が漢数字なら、変数 $numstr に代入し、$flag をTRUEにする。
前の形態素が漢数字でなく、その形態素が漢数字でなければ、そこで漢数字が終了したものとみなし、ユーザー関数 kan2num を使って半角数字に変換する。ユーザー関数 kan2num は、「PHPで半角数字を漢数字にする」で作ったユーザー関数だ。

ここで注意が必要なのが、漢数字に続く形態素の品詞である。
例文で「千本」の部分は、「千(名詞)」と「本(接尾語)」に分解される。これはそのまま kan2num を使って半角数字「1000本」に変換すればいい。
一方、「千灯明」の部分は、「千(名詞)」と「灯明(名詞)」に分解される。これをそのまま半角数字に変換すると、「1000灯明」となってしまう。
そこで、漢数字の後に名詞が続く場合は、2つの形態素を合わせて1つの名詞とみなし、変換を行わないようにした。
参考サイト
- 日本語形態素解析Webサービス:Yahoo!JAPAN デベロッパーネットワーク
- PHPで形態素解析を行う:ぱふぅ家のホームページ
- PHPで半角数字を漢数字にする:ぱふぅ家のホームページ
「八戸市」「千灯明」といった名詞に含まれる漢数字を半角数字に変換しないようにするため、「PHPで形態素解析を行う」で紹介した「日本語形態素解析Webサービス」を利用する。
(2022年1月30日)PHP8対応,リファラ・チェック改良,https対応