マクロツイーター

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

xeCJK で CheckSingle で BMP 外の文字を書くとアレ

zxjatype で「花園明朝B」をフォールバックに使うと上手くいかないという報告をもらった。調べてみると、次のような場合にエラーになるようだ。(^^^^4e01 は XeTeX の「拡張 TeX エスケープ形式」で U+4E01 の文字を書いたのと同値になる。数字が 5 桁の場合は ^^^^^20001^ も 5 つにする。)

% XeLaTeX 文書; 文字コードは UTF-8
\documentclass{article}
\usepackage[AutoFallBack=true]{zxjatype}
\setjamainfont{HanaMinA}% 明朝→花園明朝A
  % 明朝フォールバック→花園明朝B(色を付けた)
\setCJKfallbackfamilyfont{rm}[Color=00993300]{HanaMinB}
\begin{document}
^^^^4e01^^^^4e02^^^^4e03 ^^^^^20001^^^^^20002^^^^^20003
\end{document}
! Missing \endcsname inserted.
<to be read again>
                   \__int_eval_end:
l.7 ^^^^4e01^^^^4e02^^^^4e03 ^^^^^20001
                                       ^^^^^20002^^^^^20003
?
アレなのは何か

ただ、この場合も、^^^^^20001 の前の空白を消すと全て(フォールバック処理も含めて)正常に出力される。だから zxjatype の独自の処理*1もフォールバック処理も関係なさそうだ。

さらに調べてみた結果、このエラーは以下の状況で起こることが解った:

  • CheckSingle=true(文字ウィドウ抑止)にしている。(このオプションの既定値は xeCJK では偽であるが、zxjatype では真にしている。)
  • BMP 外の文字を含んだテキストを入力している。

例えば、次のようなソースでエラーを再現できる。

% XeLaTeX 文書; 文字コードは UTF-8
\documentclass{article}
\usepackage[CheckSingle=true]{xeCJK}
\setCJKmainfont{HanaMinA}
\begin{document}
% エラー!
^^^^4e01^^^^4e02^^^^4e03 ^^^^^2000b
\end{document}

(ただどういうテキストでエラーになるかの詳細は不明で、例えば上の例で空白の前が 2 文字だとエラーにならない。)

BMP 内と外で異なる挙動を示すことは、TeX 言語上の仕様では本来ないはずである。そうなると XeTeX の動作自体が怪しい。*2さらに調べてみると、「BMP 外の文字トークンに対する \meaning の動作に不具合があることが判明した。(環境は Windows 上の TeX Live 2013。)

% plain XeTeX document
\def\inspect#1{\expandafter\inspectA\meaning#1XY\relax#1}
\def\inspectA#1 #2 #3#4#5\relax#6{\number`#3:\number`#4:#5:\number`#6}
\message{\inspect ^^^^4e01}
\message{\inspect ^^^^^20001}
\bye

これを実行すると次のように端末に出力される。

19969:88:Y:19969 55360:56321:XY:131073
(19969 = 0x4E01; 55360 = 0xD840; 56321 = 0xDC01; 131073 = 0x20001)

〉のような文字トークンに \meaning を適用すると、「the letter あ」のような \the-文字列が得られる。この中の〈〉は当然元の文字トークンと同じ符号位置を持っているはずだが、元の文字が BMP 外の場合、ここが「サロゲートペアの符号位置のトークン 2 つ」に分裂してしまっているようである。

回避策

先述の \meaning の問題は CheckSingle(文字ウィドウ抑止)の処理の中で発生する。だから、取りあえずこれを無効にすると回避できる。zxjatype の場合は noCJKchecksingle というオプションを指定する。

% XeLaTeX 文書; 文字コードは UTF-8
\documentclass{article}
\usepackage[AutoFallBack=true,noCJKchecksingle]{zxjatype}
\setjamainfont{HanaMinA}
\setCJKfallbackfamilyfont{rm}[Color=00993300]{HanaMinB}
\begin{document}
^^^^4e01^^^^4e02^^^^4e03 ^^^^^20001^^^^^20002^^^^^20003
\end{document}

*1:現状ではほとんど存在しないのであるが

*2:XeTeX の内部では UTF-16 が使われているようである。外からは見えないのであるが。