こんにちは、高木です。
PHPでC言語の前処理を行う話題が続いています。今回もその一環なのですが、無理にPHPを使わなくてもほかの方法でも実現できると思います。せっかくなのでPHPでやろうというだけのことです。
やろうとしているのは、Unicode(というかUTF-16)からシフトJISへの変換表を作りたいと思います。最近のPC向け処理系であれば、何らかの変換ライブラリが使えると思いますので、それらを使えばいいと思います。しかし、マイコンなどでは変換ライブラリがない場合も多いため、どうしても変換表の自作が必要になります。
今回は安直に、U+0000からU+FFFFの65,536要素の配列にしようと思います。ほとんどが変換できないためにゼロで埋めることになるでしょうが、複雑なことをすればそれだけ間違いも多いですので、できるだけシンプルな方法を採用することにしました。
それではコードを見ていきます。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<?php function make_utf16_to_cp932_table(): string { $r = "const uint16_t utf16_to_cp932_table[] = {" . PHP_EOL; for ($utf16 = 0x0000; $utf16 < 0x10000; ++$utf16) { if (($utf16 & 0xf) == 0) $r .= " "; $cp932 = mb_convert_encoding(pack('n', $utf16), 'cp932', 'utf-16be'); if ($cp932 === false || strlen($cp932) < 2) // 変換失敗 { $r .= '0x0000, '; } else // 変換成功 { $t = unpack('C*', $cp932); $r .= sprintf("0x%02x%02x, ", $t[1], $t[2]); } if (($utf16 & 0xf) == 0xf) $r .= sprintf('/* U+%04x - U+%04x */', $utf16 & 0xfff0, $utf16) . PHP_EOL; } $r .= "};" . PHP_EOL; return $r; } ?> |
作成する関数はmake_utf16_to_cp932_tableになります。この関数を実行すると、utf16_to_cp932_tableという配列が生成されます。配列の要素の方はuint16_t型になっていますので、実際に使用する際は<stdint.h>をインクルードする必要があります。C99より前の規格に準じた処理系であれば、unsigned short型などに変更する必要があるでしょう。
make_utf16_to_cp932_table関数では、0x0000から0xffffまでの値を取る$utf16をUTF-16の値に見立てて、mb_convert_encoding関数でCP932に変換しています。CP932はシフトJISのマイクロソフト方言だと思ってください。
mb_convert_encoding関数は文字列しか受け取れませんので、pack関数でUTF-16BEに変換してからCP932に変換するようにしています。変換できなかった場合は0x0000を配列の要素に埋め込んでいます。変換できた場合、今度は2バイトのCP932の文字を16ビットの整数値にunpack関数で変換したものを配列の要素に埋め込んでいます。