マクロツイーター

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

きょうの XeTeX (2) : \XeTeXinputnormalization

「XeTeX で Unicode 正規化する件」に関するプリミティブ。

  • \XeTeXinputnormalization :[整数パラメタ・読書可] テキスト行読込の際に適用される正規化の種類を指定する: 0=処理なし、1=NFC、2=NFD。

例えば、

\XeTeXinputnormalization=1
% これ以降はNFCに正規化される

を実行すると、それ以降の行の読込の際に、字句解析より前に NFC 正規化が適用される。(行単位であることに注意。)

「文字列に対して 1 文字ずつ何らかの処理を行う」ようなマクロは、「複数の Unicode 文字の結合で表される文字」(例えば分解された形の濁点付き仮名文字など)が入力に含まれると意図せぬ動作を起こす場合がある。

% plain XeTeX 文書, 文字コードUTF-8
%\XeTeXinputnormalization=1 % NFCに正規化
\font\fIpxm="IPAexMincho" \fIpxm
% \insertDots{<文字列>}
\def\insertDots#1{\insertDotsA#1\relax}
\def\insertDotsA#1{#1\insertDotsB}
\def\insertDotsB#1{\unless\ifx#1\relax#1\expandafter\insertDotsB\fi}
% 使ってみる
\insertDots{おもてなし}\par
\insertDots{ろくでなし}\par %<で>はNFC(3067)
%↓うまくいきません
\insertDots{ろくでなし}\par %<で>はNFD(3066 3099)
\bye

こういう場合に NFC への正規化を行うと問題が避けられるかも知れない。*1先のソースの場合、2 行目のコメントアウトを外して

\XeTeXnormalization=1 % NFCに正規化

を有効にすると、全てが期待通りの出力になる。

注意であるが、正規化処理は、XeTeX が最初にソース行を読むときに行われる。だから以下のようなコードは上手くいかない。要するに、カテゴリコード変更(\catcode)と同様の注意が必要である。

% 一時的に正規化有効にしてマクロを実行したいが…
\insertDotsNfc#1{%
  \XeTeXinputnormalization=1
  \insertDots{#1}%
  \XeTeXinputnormalization=0 }

もちろん、正規化を行う以上、Lost in N11n が不可避であることにも注意が要る。

% plain XeTeX 文書, 文字コードUTF-8
\font\fIpxm="IPAexMincho" \fIpxm% 互換漢字(FA19)
%\XeTeXinputnormalization=1 % NFCに正規化% Lost in normalizaion!
\bye

そういうわけなので、この機能を使う機会はあまり無いように思われる。なお、「そもそも文字の出力するのに NFC に正規化しなくてもよいのか」という疑問をもつ人もいると思うが、これについてはまた別の記事に述べたい。

*1:もちろん、“合成済”の文字が Unicode に非登録の場合(例えば〈か+半濁点〉など)は NFC にしても分解されたままなので、正規化を行うことは本質的な解決にはならない。