PHPで半角数字を漢数字にする

(1/1)
パソコンの画面は、そのほとんどが横書きだが、縦書きスタイルで印刷するような場面がある。こんな時、スタイルを変更するだけでデータそのものは簡単に二次利用ができるのが電子ファイルの強みである。
しかし、スタイルとして縦書き用フォントを適用しても、半角数字を縦書きにすることはできない。組文字を使うなどの手はあるが、やはり漢数字で縦書きにした方が見やすい。
そこで今回は、半角数字を漢数字に変換する PHP プログラムを作ってみることにする。

(2021 年 5 月 30 日)PHP8 対応,リファラ・チェック追加

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

PHPで半角数字を漢数字にする

サンプル・プログラム

圧縮ファイルの内容
num2kanji.phpサンプル・プログラム本体。

変換ルール(1)通常記法

0148: /**
0149:  * 半角数字を漢数字に変換する(通常記法)
0150:  * @param   string $instr 半角数字
0151:  *                          小数、負数に対応;指数表記には未対応
0152:  *                          カンマは無視
0153:  * @return  string 漢数字
0154: */
0155: function num2kan_normal($instr) {
0156:     static $kantbl = array(0=>'', 1=>'', 2=>'', 3=>'', 4=>'', 5=>'', 6=>'', 7=>'', 8=>'', 9=>'', '.'=>'', '-'=>'');
0157: 
0158:     $outstr = '';
0159:     $len = strlen($instr);
0160:     for ($i = 0; $i < $len$i++) {
0161:         $ch = substr($instr$i, 1);
0162:         if ($ch == ',')    continue;        //カンマは無視
0163:         $outstr .= (isset($kantbl[$ch]) ? $kantbl[$ch] : '');
0164:     }
0165: 
0166:     return $outstr;
0167: }

新聞の西暦年号でよく見かける、「2008 年(平成 20 年)」を「二〇〇八年」に変換するルールを「通常記法」と呼ぶことにする。

この処理は、ユーザー関数 num2kan_normal が担当している。
プログラム的には難しいものではない。引数を 1 文字ずつ取り出して、対応する漢数字に置き換えているだけである。
置換テーブルは連想配列 $kantbl として用意し、変換元文字を添字に、変換後の文字を変数値としている。こういう時に連想配列は便利である。

変換ルール(2)位取り記法

0169: /**
0170:  * 半角数字を漢数字に変換する(位取り記法)
0171:  * @param   string $instr 半角数字
0172:  *                          小数、負数に対応;指数表記には未対応
0173:  *                          カンマは削除
0174:  * @return  string 漢数字
0175: */
0176: function num2kan_decimal($instr) {
0177:     static $kantbl1 = array(0=>'', 1=>'', 2=>'', 3=>'', 4=>'', 5=>'', 6=>'', 7=>'', 8=>'', 9=>'', '.'=>'', '-'=>'');
0178:     static $kantbl2 = array(0=>'', 1=>'', 2=>'', 3=>'');
0179:     static $kantbl3 = array(0=>'', 1=>'', 2=>'', 3=>'', 4=>'');
0180: 
0181:     $outstr = '';
0182:     $len = strlen($instr);
0183:     $m = (int)($len / 4);
0184:     //一、万、億、兆‥‥の繰り返し
0185:     for ($i = 0; $i <= $m$i++) {
0186:         $s2 = '';
0187:         //一、十、百、千の繰り返し
0188:         for ($j = 0; $j < 4; $j++) {
0189:             $pos = $len - $i * 4 - $j - 1;
0190:             if ($pos >= 0) {
0191:                 $ch  = substr($instr$pos, 1);
0192:                 if ($ch == ',')    continue;        //カンマは無視
0193:                 $ch1 = isset($kantbl1[$ch]) ? $kantbl1[$ch] : '';
0194:                 $ch2 = isset($kantbl2[$j])  ? $kantbl2[$j]  : '';
0195:                 //冒頭が「一」の場合の処理
0196:                 if ($ch1 != '') {
0197:                     if ($ch1 == '' && $ch2 != '') $s2 = $ch2 . $s2;
0198:                     else                                $s2 = $ch1 . $ch2 . $s2;
0199:                 }
0200:             }
0201:         }
0202:         if ($s2 != '')  $outstr = $s2 . $kantbl3[$i] . $outstr;
0203:     }
0204: 
0205:     return $outstr;
0206: }

「1,234,567」を「百二十三万四千五百六十七」に変換するルールを「位取り記法」と呼ぶことにする。

漢数字の位取りは 4 桁毎である。すなわち、「一、十、百、千」の 4 桁で回るループと、その外側の「一、万、億、兆‥‥」の 2 つの組み合わせからなる。
さらに、一の位以外で「一」があらわれる場合は、これを無視する。「一百万」「一十億」とは記さないからである。
これをプログラムにしたのがユーザー関数 num2kan_decimal である。

正規表現による置換

0291: //変換
0292: if (isButton('exec')) {
0293:     //位取記法
0294:     if ($mode['decimal'] != '') {
0295:         $dest = preg_replace_callback('/[0-9.\.\-\,]+/msu',
0296:                 function ($mt) {
0297:                     return num2kan_decimal($mt[0]);
0298:                 }, $sour
0299:             );
0300:     //通常記法
0301:     } else {
0302:         $dest = preg_replace_callback('/[0-9.\.\-\,]+/msu',
0303:                 function ($mt) {
0304:                     return num2kan_normal($mt[0]);
0305:                 }, $sour
0306:             );
0307:     }
0308: }

通常記法の場合も、位取り記法の場合も、テキスト中にあらわれる半角数字を正規表現 "/[x0-9.\.-]+/msu" を使って検出し、関数  preg_replace_callback  によって漢数字に置換している。
関数  preg_replace_callback  は、正規表現でマッチした部分文字列をユーザー関数(ここでは num2kan_normalnum2kan_decimal)に渡すことができる。

参考サイト

(この項おわり)
header