マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

\pdfstrcmp のお話 (2/3)

(前回)

\pdfstrcmp の処理が行われる時には、引数のテキストは既に TeX エンジンに読み込まれているので、非トークン化した後の比較対象となる文字列は当該エンジンの「内部文字コード」で表されていることになる。従って、基本的には文字列比較はこの「内部文字コード」の上で行われることになる。pdfTeX は本質的に 8 ビットコードしか扱わない(inputenc で UTF-8 を読む場合も結局バイト単位でマクロが動いている)ので各バイトの値により比較が行われる((inputenc 使用時は非 ASCII 文字を構成する各バイトは実際にはマクロになっているため、\pdfstrcmp の引数に単純に入れることはできない。))。

すると、Unicode をネイティブに扱う TeX エンジン(XeTeX/LuaTeX)の場合はに予想される結果は「各文字の Unicode の符号値により比較される」であろう。ところが、実際の XeTeX はそうならない。


% 文字コードUTF-8; 文書の一部
\strcmp{$}{𡈽} %〈$〉= U+FF04;〈𡈽〉= U+2123D

これの出力は「1」(U+FF04 の方が U+2123D より大)となる。この理由は XeTeX の「内部文字コード」が UTF-16 であるから((Jonathan Kew が著した文書でそういう記述があるのを見た記憶がある。初期の XeTeX は BMP 外の文字の扱いに制限(例えば \catcode が指定できない、等)があった。))、U+FF04 はそのまま〈FF04〉であるのに対し BMP 外の U+2123D は〈D844 DE3D〉と表わされる(FF04 > D844)からである。もちろん、現在の XeTeX は BMP 外の文字も BMP 内の文字と全く同様に取り扱えるのだが、このような点に UTF-16 の影響が表れていることが判る。

それでは、前回示した LuaTeX 用の \pdfstrcmpLua での実装はどうか。実は Lua は最近のスクリプト言語としては珍しく 8 ビット符号しか扱わない言語仕様になっていて(「実装をコンパクトにする」という理念のため複雑な機能が意図的に省かれている)、従って、「文字列」は常に何らかの文字コードによりエンコードした「バイト列」として扱うことになる。LuaTeX では TeX 上の文字列を Lua に渡す時には UTF-8 でのエンコードを行っている。従って、例の \pdfstrcmp は実際には UTF-8 のバイト列を比較していることになる。しかし実は「文字列に対する、UTF-8 のバイト列での比較結果と Unicode 符号値の列での比較結果は常に一致する」という性質が成立するので、結果的に例の実装は先述の「期待した結果」(Unicode 符号値での比較)になっている。

e-pTeX の場合、「内部文字コード」が欧文(8 ビット)と和文sjis または euc)で完全に分かれているので複雑になる。(角藤氏の実装について)結論を言うと、和文文字を UTF-8 の表現に変換(欧文はそのまま)してできるバイト列で比較を行うようである。内部和文文字コードの違いによる結果の差異を避けるために敢えて和文を一定のバイト列に変えていると思われる。


% 文字コードは -kanji で指定のもの; 文書の一部
% ^^e3 等のカテゴリコードは 12 とする
\strcmp{^^e3^^81^^82}{あ} %〈あ〉= U+3042; UTF-8 で E3 81 82

これは e-pLaTeX と e-upLaTeX の両方で、また入力漢字コード(-kanji)と内部漢字コード(-kanji-internal)の値が何であっても「0」を出力する(等しいバイト列と判断する)。なお、先述の UTF-8 のバイト列に関する性質から、和文文字だけに関していえば「Unicode 符号値での比較」と一致している。