日頃日本語組版の作業をしていると,
- この人名漢字って JIS (ISO-2022-JP) で表現可能な JIS X 0208 の範囲に入っていたっけ?
- JIS X 0208 の xx区yy点 に相当する文字は何だっけ? その Unicode 符号位置はどこかな?
- この文字の UTF-8 表現のバイト列は? EUC-JP では? Shift-JIS では?
- この旧字体は Unicode BMP 外だったっけ?
- このBMP外文字のサロゲートペアはどの符号位置に来る?
といった疑問を抱く場面に多々出会います。
そういうとき,いちいち文字コード表にあたって調べるのは面倒なので,TeX (upTeX) の機能を使って,このような疑問に全自動で答えられるようにすることを目指しました。
目標1:JIS X 0208 の区点位置から文字コード情報を得る
JIS X 0208 の「xx区yy点」という区点位置が与えられたとき,そこから以下の情報を取得する。
- 文字
- Unicode 符号位置
- UTF-16 表現(ビッグエンディアン・リトルエンディアン)のバイト列
- UTF-8 表現のバイト列
- JIS (ISO-2022-JP) 表現のバイト列
- EUC 表現のバイト列
- Shift-JIS 表現のバイト列
そして,次のような表を作成する。
目標2:入力された文字の文字コード情報を得る
UTF8で作成されたTeXソースに入力された文字から,以下の情報を取得する。
- Unicode 符号位置
- BMP外の場合はサロゲートペア
- UTF-16 表現(ビッグエンディアン・リトルエンディアン)のバイト列
- UTF-8 表現のバイト列
- その文字が JIS X 0208 の範囲に含まれるかどうか調べる。含まれていた場合は,次も調べる。
- JIS (ISO-2022-JP) 表現のバイト列
- EUC 表現のバイト列
- Shift-JIS 表現のバイト列
そして,次のような表を作成する。
実装方針
JIS区点位置 → JIS / EUC / SJIS バイト列
JIS / EUC / SJIS の符号化は,いずれも JIS X 0208 の区点位置をベースにしています。*1 したがって,JIS 区点位置が与えられれば,JIS / EUC / SJIS 表現のバイト列は機械的に計算で求めることができます。それを TeX の演算機能で実装します。
JIS区点位置 → Unicode符号位置
pTeX には,JIS 区点コードから pTeX の内部コードへ変換する \kuten
というプリミティブが提供されています。これは upTeX にも引き継がれています。*2
そこで,upTeX の \kuten
を利用して JIS 区点コードから Unicode 文字に変換したものを \chardef
でトークン化し,その \meaning
の出力*3を解析することで,Unicode の符号位置を得ることができます。
入力文字 → Unicode符号位置
同様に,入力された文字を \chardef
でトークン化したものを \meaning
することで,入力文字の Unicode 符号位置を得ることができます。
Unicode符号位置 → UTF-16 / UTF-8 バイト列
Unicode の符号位置を符号化するルールを TeX で実装すれば,UTF-16 や UTF-8 で符号化されたバイト列が得られます。UTF-16 で符号化するときはサロゲートペアやエンディアンにも注意します。
Unicode符号位置 → JIS区点位置
この「逆変換」部分は難関です。Unicode には当然 JIS X 0208 以外の文字もたくさんありますので,Unicode → JIS X 0208 の対応はいつでも付けられるわけではありません。また,対応が付けられる文字についても,どうやって逆方向に対応づけるか,その名案が思いつきません。
そこで,最も愚直な方法をとることにしました。Unicode の文書にある JIS X 0208 → Unicode のマッピング をもとに,逆変換である Unicode → JIS X 0208 の対応表(6879文字分)を作成し,TeX の制御綴にセットして毎回走査するという方法です。
実装:upjcode パッケージ
以上の方針に従って実装したものを,upjcode パッケージ としてまとめました。
インターフェース(JIS区点位置からの変換)
JIS区点位置 → 文字
\kutenToChar{区}{点}
JIS X 0208 の区点位置で指定された文字を出力する。引数には区点それぞれの位置を10進整数で指定する。
JIS区点位置 → Unicode符号位置
\kutenToCodePoint[プレフィックス]{区}{点}
JIS X 0208 の区点位置で指定された文字の Unicode 符号位置を U+xxxx の形式で出力する。
オプション引数 [プレフィックス]
の部分を明示指定することで "U+" の部分を変更可能。
JIS区点位置 → UTF-16表現
\kutenToUTFSixteen[エンディアン]{区}{点}
JIS X 0208 の区点位置で指定された文字を UTF-16 で符号化したときのバイト列を16進で出力する。
デフォルトではビッグエンディアンで符号化するが,[エンディアン]
の部分に [LE]
と指定するとリトルエンディアンで符号化する。
JIS区点位置 → UTF-8表現
\kutenToUTFEight{区}{点}
JIS X 0208 の区点位置で指定された文字を UTF-8 で符号化したときのバイト列を16進で出力する。
JIS区点位置 → JIS (ISO-2022-JP) 表現
\kutenToJIS{区}{点}
JIS X 0208 の区点位置で指定された文字を JIS (ISO-2022-JP) で符号化したときのバイト列を16進で出力する。
JIS区点位置 → EUC-JP表現
\kutenToEUC{区}{点}
JIS X 0208 の区点位置で指定された文字を EUC-JP で符号化したときのバイト列を16進で出力する。
JIS区点位置 → Shift-JIS表現
\kutenToSJIS{区}{点}
JIS X 0208 の区点位置で指定された文字を Shift-JIS で符号化したときのバイト列を16進で出力する。
インターフェース(直接文字入力からの変換)
直接入力文字 → Unicode符号位置
\getCodePoint{文字}
文字
の Unicode 符号位置を取得し,TeX カウンタ \UnicodePoint
に保存する。
\charToCodePoint[プレフィックス]{文字}
文字
の Unicode 符号位置を TeX カウンタ \UnicodePoint
に保存しつつ,U+xxxx という文字列で出力する。"U+" というプレフィクス部分はオプション引数 [プレフィックス]
でカスタマイズ可能。
\charToCodePoint*[プレフィックス]{文字}
とすると,文字
がBMP外の場合に,サロゲートペアを (U+xxxx U+xxxx) のように補足表示する("U+" の部分は [プレフィックス]
の指定に従う)。
サロゲートペアの補足情報表示書式は,\printSurrogatePair
というマクロの定義を改変することでカスタマイズ可能。
直接入力文字 → UTF-16表現
\charToUTFSixteen[エンディアン]{文字}
文字
を UTF-16 で符号化したときのバイト列を16進で出力する。
デフォルトではビッグエンディアンで符号化するが,[エンディアン]
の部分に [LE]
と指定するとリトルエンディアンで符号化する。
直接入力文字 → UTF-8表現
\charToUTFEight{文字}
文字
を UTF-8 で符号化したときのバイト列を16進で出力する。
直接入力文字 → JIS区点位置
\charToKuten{文字}
文字
の JIS X 0208 区点位置を検索する。6879文字分を走査するのでかなり時間がかかる。
次の結果をもたらす。
- 探索した文字の Unicode 符号位置は TeX カウンタ
\UnicodePoint
に保存する。 - JIS X 0208 に対応する文字が見つかった場合
- TeX カウンタ
\jisKu
,\jisTen
に区点番号をセットする。 \printKutenPoint{区}{点}
に展開されるマクロ\kutenResult
を定義する。\printKutenPoint
はデフォルトでは\def\printKutenPoint#1#2{#1区#2点}
と定義されたマクロ。これをカスタマイズすることで区点位置の出力書式をカスタマイズ可能。
- TeX カウンタ
- JIS X 0208 に対応する文字が見つからなかった場合
- TeX カウンタ
\jisKu
,\jisTen
に 0 をセットする。 \let\kutenResult\kutenNotFound
とする。\kutenNotFound
はデフォルトでは\def\kutenNotFound{-}
と定義されたマクロ。
- TeX カウンタ
テストソース
upjcode パッケージ を使って文字コード情報を調べるテストソースです。
コンパイル結果
上記ソースを uplatex でコンパイルすると,次の出力が得られます。
これで文字コードを検索する手間が省けて楽になりますね!