マクロツイーター

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

きょうの e-TeX (4): \iffontchar

  • \iffontchar〈フォント〉〈符号位置〉 :[if-トークン] 指定のフォントに指定の符号位置の文字が存在するかを判定する。

ここで、〈フォント〉は次の何れかである:

  • \font : 現在のテキストフォントを表す。
  • fontdef トークン : \font〈トークン〉=... で定義されるトークン。
  • \scriptfont2 等の現在の数式フォントを指定する書式。

LaTeX 上の TeX プログラミングでは後の 2 つを扱う機会はほとんどないので、専ら \iffontchar\font〈符号位置〉 の形で用いることになると思われる。有効な〈符号位置〉の範囲は、8 ビット TeX では 0〜255 だが、Unicode TeX では Unicode 符号空間全体となる(e-(u)pTeX については後述)。

例えば、plain XeTeX で以下のようにしてフォントに存在する全部の文字(全グリフではない)を出力させることができる:


\font\target="IPAex明朝"
\newcount\uc
\noindent \target
\uc=0 \loop
\iffontchar\font\uc \char\uc \hskip0pt plus1pt\relax \fi
\advance\uc1
\ifnum\uc<"30000 \repeat
\bye

この命令が e-TeX 拡張であるということは、つまり、非 e-TeX においてはフォントに文字が実際に存在するかを確実に判定する手段がないということである。どうしてもその処理が必要な場合に代替として考えられるのは、該当の文字を含むボックスを作ることで、その文字の幅・高さ・深さが全てゼロである場合にのみ存在しないと判定する方法である。


\setbox0{\tracinglostchars=0 \char〈符号位置〉}
% (\tracinglostchars=0 は非存在の文字の警告を消す設定)
\@tempswatrue
\ifdim\wd0=0pt \ifdim\ht0=0pt \ifdim\dp0=0pt \@tempswafalse \fi\fi\fi
\if@tempswa 〈存在する〉 \else 〈存在しない〉 \fi

私自身は、幅・高さ・深さが全てゼロでしかも「有効な」文字を含む TeX フォントは見たことがないが、TeX においてはそういう「文字」が必要な処理がありえそうなので、この判定法は完全ではない。確実に判定するには e-TeX 拡張の \iffontchar が必須である。

最後に、e-(u)pTeX和文フォントについて述べておく。pTeX およびその派生エンジンでは、和文フォントについては、その有効な符号空間の全部の文字が、あたかも常に存在するかのように動作する(これは和文 TFM の設計に起因する)。例えば、jsarticle クラスで標準で使われる和文フォント jis は(少なくとも dvips/dvipdfmx の処理では*1)本来の JIS X 0208 に従うので、所謂「Windows 依存文字」の〈①〉(符号位置 0x2D21)は含んでいないはずである。ところが、jis を使う設定で〈①〉を出力するような TeX 文書を (e-)pTeX組版すると、pTeX は文字の存在に関与しないので、そのまま「jis の 0x2D21」を含む DVI を出力してしまう。実際にエラーが起こるのは dvips/dvipdfmx でその DVI を処理する時になる。

このことを考えると、和文において「役に立つ」形で \iffontchar を実装するのは(和文 TFM の構造に更なる拡張がなされない限り)原理的に不可能である。pTeX(および派生)では、\font和文に相当するものとして、\jfont(横書き)と \tfont(縦書き)が用意されている。そして、現状の e-(u)pTeX では \iffontchar\jfont... 等はデタラメな結果を出すように見える。勿論、「正しい実装」は恐らく「常に真」を返すというものであり、結局それは役に立たない。

*1:dviout では JIS 符号系のフォントは実際には CP932 の文字集合をもつように扱われる。ただ私は、pTeX 標準の JY1 エンコーディング(jis や min10 はこれに属する)は常に(dviout を使う場合でも)JIS X 0208 を表すと考えるべきだと思っている。