読者です 読者をやめる 読者になる 読者になる

TeX Alchemist Online

TeX を使って化学のお仕事をしています。

upTeX で文字コード情報を調べる upjcode パッケージ

フォント TeX

日頃日本語組版の作業をしていると,

といった疑問を抱く場面に多々出会います。

そういうとき,いちいち文字コード表にあたって調べるのは面倒なので,TeX (upTeX) の機能を使って,このような疑問に全自動で答えられるようにすることを目指しました。

目標1:JIS X 0208 の区点位置から文字コード情報を得る

JIS X 0208 の「xx区yy点」という区点位置が与えられたとき,そこから以下の情報を取得する。

  • 文字
  • Unicode 符号位置
  • UTF-16 表現(ビッグエンディアン・リトルエンディアン)のバイト列
  • UTF-8 表現のバイト列
  • JIS (ISO-2022-JP) 表現のバイト列
  • EUC 表現のバイト列
  • Shift-JIS 表現のバイト列

そして,次のような表を作成する。

f:id:doraTeX:20150218195429p:plain

目標2:入力された文字の文字コード情報を得る

UTF8で作成されたTeXソースに入力された文字から,以下の情報を取得する。

  • Unicode 符号位置
  • BMP外の場合はサロゲートペア
  • UTF-16 表現(ビッグエンディアン・リトルエンディアン)のバイト列
  • UTF-8 表現のバイト列
  • その文字が JIS X 0208 の範囲に含まれるかどうか調べる。含まれていた場合は,次も調べる。
    • JIS (ISO-2022-JP) 表現のバイト列
    • EUC 表現のバイト列
    • Shift-JIS 表現のバイト列

そして,次のような表を作成する。

f:id:doraTeX:20150218195619p:plain

実装方針

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点} と定義されたマクロ。これをカスタマイズすることで区点位置の出力書式をカスタマイズ可能。
  • JIS X 0208 に対応する文字が見つからなかった場合
    • TeX カウンタ \jisKu, \jisTen に 0 をセットする。
    • \let\kutenResult\kutenNotFound とする。\kutenNotFound はデフォルトでは \def\kutenNotFound{-} と定義されたマクロ。

テストソース

upjcode パッケージ を使って文字コード情報を調べるテストソースです。

コンパイル結果

上記ソースを uplatex でコンパイルすると,次の出力が得られます。

f:id:doraTeX:20150218195119p:plain

これで文字コードを検索する手間が省けて楽になりますね!

*1:JIS X 0201 の半角カナや JIS X 0212 の補助漢字などを除く。

*2:pTeX では変換先の内部コードは EUC ベースであったのに対し,upTeX では内部コードが Unicode ベースに変更されています。

*3:\char"FA1F のような出力になります。