
(2021年2月6日)-g オプションを追加。
(2021年1月2日)40ビット以上のUnicodeで文字化けが起きる不具合を修正。
目次
サンプル・プログラムの実行例

たとえば
<img src="itaiji.php=?g=908A_E0109" /> は 邊 の異体字です。
のようにして使うことができる。-gオプション のあとに、IVS(後述)を指定する。
サンプル・プログラム
itaiji.php | サンプル・プログラム本体 |
mji.00601.sqlite3 | MJ文字情報一覧表(SQLite3データベース) |
mji2sql.vbs | MJ文字情報一覧表(Excelファイル)からSQLite3データベースを生成するVBScript |
準備:MJ文字情報一覧表
だが、このAPIは試験的なものであり、2020年(令和2年)8月、文字情報基盤の成果物がIPAから一般社団法人文字情報技術促進協議会に移管したことから、停止する可能性がある。(2021年9月現在、利用できなくなっている)
そこで今回は、文字情報技術促進協議会に移管された「MJ文字情報一覧表」を利用することにする。

MJ文字情報一覧表は、前述の6万文字を超える漢字の一覧表である。
Strict Open XML形式のExcelファイルとしてダウンロードできるのだが、PhpExcel や Google Spreadsheet などの既製ライブラリを使ってオープンすることができない。Excelも2007ではオープンできず、Microsoft 365 を使ってオープンできることが分かった。
そこで、ダウンロードしたMJ文字情報一覧表を、Microsoft 365 を搭載したPC上で VBScript を使って読み込み、SQLite データベースに変換し、PHPから利用できるようにする方針を立てた。

SQLite データベースを生成するため、SQLite ODBCドライバを用意する。
公式サイトから SQLite ODBC Driver をダウンロードする。64ビット版でも、32ビット版の "sqliteodbc.exe" をダウンロードし、インストールするといいようだ。

Microsoft 365 と SQLite ODBC Driver が用意できたら、次の手順で MJ文字情報一覧表をデータベースに変換する。
- MJ文字情報一覧表をダウンロードし、解凍する。"mji.00601.xlsx" という約7.5Mバイトのファイルができる。
- 同梱のVBScript "mji2sql.vbs" を実行する。MJ文字情報一覧表ファイルは変数 fnameMJ に、SQLiteデータベース・ファイルは DBname にフルパスで記述すること。DBname は書き込み権限があるパスを指定する。
- しばらくすると、SQLiteデータベース・ファイルができる。PHPから参照できるフォルダへ移動する。
MJ文字情報一覧表:テーブル定義
mj:MJ文字情報一覧表 | |||
---|---|---|---|
No. | 名前 | 型 | 内容 |
1 | MJcode | テキスト | MJ文字図形名 |
2 | ucs | テキスト | 実装したUCS:プライマリキー |
3 | ivs | テキスト | 実装したMoji_JohoコレクションIVS |
4 | koseki | テキスト | 戸籍統一文字番号 |
5 | juki | テキスト | 住基ネット統一文字コード |
6 | sesaku | テキスト | 漢字施策:常用漢字、人名漢字 |
1 | yomi | テキスト | 読み(参考):音読みは片仮名、訓読みは平仮名。 |
準備:IPAmj明朝フォント
文字情報技術促進協議会からダウンロード、解凍すると、"ipamjm.ttf" という約46M バイトの巨大なフォントファイルが取り出せる。
これを、PHPから参照できるフォルダに配置する。
解説:初期値
37: //入力文字(デフォルト)
38: define('DEF_SOUR', '邊');
39:
40: //MJ文字情報一覧表(SQLiteデータベース)
41: define('DBFILE', './mji.00601.sqlite3');
42:
43: //検索SQL(※変更不可)
44: define('PRE_SELECT', 'SELECT MJcode, ivs FROM mj WHERE ucs=:ucs;');
45: define('PRE_SELECT_IVS', 'SELECT MJcode, ivs FROM mj WHERE ivs=:ivs;');
46:
47: //PNG画像データURL
48: //define('URL_PNG', 'https://mojikiban.ipa.go.jp/');
49: define('URL_PNG', 'https://moji.or.jp/mojikibansearch/img/MJ/');
50:
51: //IPAmj明朝フォント・ファイルの場所
52: define('IPAmj', '../../../../common/font/ipamjm.ttf');
解説:Unicodeコードポイントを求める
214: /**
215: * Unicodeコードポイントを求める
216: * @param string $ch 1文字
217: * @return string Unicodeコードポイント
218: */
219: function ch2ucp($ch) {
220: return sprintf("U+%0X", hexdec(bin2hex(mb_convert_encoding($ch, 'UCS-4', INTERNAL_ENCODING))));
221: }
解説:UnicodeコードポイントからUTF-8文字を求める
223: /**
224: * UnicodeコードポイントからUTF-8文字を求める
225: * @param string $ucp Unicodeコードポイント
226: * @return string UTF-8文字
227: */
228: function ucp2ch($ucp) {
229: $ch = '';
230: if (preg_match('/U\+([0-9A-F]+)/ui', $ucp, $arr) > 0) {
231: $bin = hex2bin(str_repeat('0', 8 - strlen($arr[1])) . $arr[1]);
232: $ch = mb_convert_encoding($bin, INTERNAL_ENCODING, 'UCS-4');
233: }
234: return $ch;
235: }
解説:コードポイントから異体字を求める
237: /**
238: * 異体字を求める:コードポイントから
239: * @param string $ch 1文字
240: * @param array $items 情報を格納する配列
241: * @return int 異体字の数/0:指定文字が見つからない/(-1):DBアクセスに失敗
242: */
243: function geiItaiji($ch, &$items) {
244: $ucp = ch2ucp($ch);
245:
246: //MJ文字情報一覧表(SQLiteデータベース)検索
247: try {
248: $pdo = new PDO('sqlite:' . DBFILE);
249: $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
250: $stmt = $pdo->prepare(PRE_SELECT);
251: $stmt->bindValue(':ucs', $ucp, PDO::PARAM_STR);
252: $stmt->execute();
253: $cnt = 0;
254: while ($row = $stmt->fetch()) {
255: //画像ファイルのURL
256: $items[$cnt]['png'] = URL_PNG . $row['MJcode'] . '.png';
257: //HTMLエンティティ
258: if (preg_match('/([0-9A-Z]{4,6})\_([0-9A-Z]{5})/ui', $row['ivs'], $arr) > 0) {
259: $items[$cnt]['itaiji1'] = '&#x' . $arr[1] . ';&#x' . $arr[2] . ';';
260: } else if (preg_match('/U\+([0-9A-Z]{4,6})/ui', $ucp, $arr) > 0) {
261: $items[$cnt]['itaiji1'] = '&#x' . $arr[1] . ';';
262: } else {
263: $items[$cnt]['itaiji1'] = '';
264: }
265: //HTMLエンティティ(エンコード)
266: $items[$cnt]['itaiji2'] = preg_replace('/&/ui', '&', $items[$cnt]['itaiji1']);
267: $cnt++;
268: }
269: $pdo = NULL;
270: } catch (PDOException $e) {
271: $cnt = -1;
272: }
273:
274: return $cnt;
275: }
解説:IVSから異体字を求める
277: /**
278: * 異体字を求める:IVSから
279: * @param string $ivs IVS
280: * @param array $items 情報を格納する配列
281: * @return int 異体字の数/0:指定文字が見つからない/(-1):DBアクセスに失敗
282: */
283: function geiItaijiIVS($ivs, &$items) {
284: //MJ文字情報一覧表(SQLiteデータベース)検索
285: try {
286: $pdo = new PDO('sqlite:' . DBFILE);
287: $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
288: $stmt = $pdo->prepare(PRE_SELECT_IVS);
289: $stmt->bindValue(':ivs', $ivs, PDO::PARAM_STR);
290: $stmt->execute();
291: $cnt = 0;
292: while ($row = $stmt->fetch()) {
293: //画像ファイルのURL
294: $items[$cnt]['png'] = URL_PNG . $row['MJcode'] . '.png';
295: //HTMLエンティティ
296: if (preg_match('/([0-9A-Z]{4,6})\_([0-9A-Z]{5})/ui', $row['ivs'], $arr) > 0) {
297: $items[$cnt]['itaiji1'] = '&#x' . $arr[1] . ';&#x' . $arr[2] . ';';
298: } else if (preg_match('/U\+([0-9A-Z]{4,6})/ui', $ucp, $arr) > 0) {
299: $items[$cnt]['itaiji1'] = '&#x' . $arr[1] . ';';
300: } else {
301: $items[$cnt]['itaiji1'] = '';
302: }
303: //HTMLエンティティ(エンコード)
304: $items[$cnt]['itaiji2'] = preg_replace('/&/ui', '&', $items[$cnt]['itaiji1']);
305: $cnt++;
306: }
307: $pdo = NULL;
308: } catch (PDOException $e) {
309: $cnt = -1;
310: }
311:
312: return $cnt;
313: }
参考サイト
- 外字が不要に――ISO/IEC 10646:2017:ぱふぅ家のホームページ
- MJ文字情報一覧表:文字情報技術促進協議会
- IPAmj明朝フォント:文字情報技術促進協議会
そこで今回は、ISO/IEC 10646:2017の異体字を表示するPHPプログラムを作ってみることにする。