Hatena::ブログ(Diary)

マクロツイーター このページをアンテナに追加 RSSフィード Twitter

2016-07-03

(u)pLaTeX で CJK パッケージする件(3)

前回の続き)

pLaTeX で和文してしかも CJK パッケージしたい場合

ざんねんでした あきらめましょう

……というのが妥当なアドバイスだと思うが、イロイロ足掻いてみる。

うまくいきません

pxCJKutf8 自体は pLaTeX でも部分的に*1動作する。ただし pTeX では非対応な \disablecjktoken については「単にそれを実行しない」という仕様になっている。従って、例の「中国語の漢字が日本語扱いされる」という問題が発生することになる。

一見すると、「和文しない」の話で出てきたように、pxfltsrc パッケージの機能をもって \disablecjktoken を代用すればいいようにも見える。

% pLaTeX 文書, 文字コードUTF-8
\documentclass[a4paper]{jsarticle}
\usepackage{pxCJKutf8,CJKspace,CJKpunct}
\usepackage[byte]{pxfltsrc}% 和文の認識を無効化
\begin{document}
\filterstart

\begin{CJK*}{UTF8}{gbsn}
{\TeX} 语言很危险,别靠近!
\end{CJK*}

% 無効化されているので"pTeXの和文"が失敗する!
{\TeX}言語危険、近づくな! % ダメ

\end{document}

しかし残念ながら今の場合はこの方法は通用しない。次のようなエラーが発生する。*2

! Package inputenc Error: Unicode char ??? (U+39EE00)
(inputenc)                not set up for use with LaTeX.

何故かというと、upLaTeX で pxCJKutf8 を用いた場合は \disablecjktoken は「CJK 環境の中だけで有効」になるのに対し、上掲のソースでは“和文の無効化”が \filterstart 以降の全体で有効になるからである。日本語の部分では「pTeX の和文」で処理させるのが目的なので、ここでは和文認識が有効になっている必要がある。

別ファイルにすればうまくいく

残念ながら、一旦 \filterstart で開始した“和文の無効化”のフィルタの効果を途中で解除する機能は用意されていない。しかし、もし CJK 環境の部分のソースだけを別ファイルに分割された状態であれば、そこだけフィルタを適用することができる。ファイル入力に対するフィルタ適用は文書途中で自由に有効化(\filterinput)・無効化(\nofilterinput)できるからである。

[main.tex]
% pLaTeX 文書, 文字コードは UTF-8
\documentclass[a4paper]{jsarticle}
\usepackage{pxCJKutf8,CJKspace,CJKpunct}
\usepackage[byte]{pxfltsrc}% 和文の認識を無効化
\begin{document}
% \filterstart はしない

\filterinput    % ファイル読込でフィルタを有効化
\input{chinese.tex}% この中身だけ和文認識が無効になる
\nofilterinput  % ファイル読込でフィルタを無効化

% ここでは和文認識が有効
{\TeX}言語危険、近づくな!

\end{document}
[chinese.tex]
\begin{CJK*}{UTF8}{gbsn}
{\TeX} 语言很危险,别靠近!
\end{CJK*}
f:id:zrbabbler:20160703225547p:image

記事が完成しました。
しかし結局かなりアレな内容なので、やっぱり
ゆきだるま☃を見てお楽しみください。

f:id:zrbabbler:20160703231546p:image

*1:つまり「\selectfontパッチが衝突する」問題への対処は upLaTE

*2:“???”の部分は文字化けして、しかも示している符号位置が不正になっている(正しくは “言 (U+8A00)”のはず)。恐らく高位バイトを含む \the-文字列を生成しようとした時に一部のバイトが和文文字として解釈されたからと思われる。なおここに示した結果は内部漢字コードが sjis の場合のものである。

2016-07-02

(u)pLaTeX で CJK パッケージする件(2)

前回の続き)

upLaTeX で和文してしかも CJK パッケージしたい場合

果たしてそんな需要があるのかは不明だが、“面白い話”なのは確かである。というわけで、作ってみた。

使い方は簡単で「CJKutf8 パッケージ(または CJK パッケージ)の代わりに pxCJKutf8 パッケージを読み込む」だけでよい。

%(例えばコレだったら)
\usepackage{CJKutf8,CJKspace,CJKpunct}
%↓(代わりにコレにする)
\usepackage{pxCJKutf8,CJKspace,CJKpunct}

なお、名前から分かるように pxCJKutf8 は「CJKutf8 の代用である」である。だから文書ファイルの文字コードUTF-8 にする必要がある*1。(日本語とそれ以外の CJK 言語が混在することになるので当然そうなっているであろう。)それさえ守られていれば、ほとんど全ての場合に「CJK パッケージの代用」として pxCJKutf8 が使える。

% upLaTeX 文書; 文字コードは UTF-8
\documentclass[uplatex,a4paper]{jsarticle}
\usepackage{pxCJKutf8,CJKspace,CJKpunct}
\begin{document}

up{\TeX}{\Large\gtfamily 日本語}できます!

\begin{CJK*}{UTF8}{gbsn}
用 CJK 宏包可以写{\Large\CJKfamily{gkai}中文}\end{CJK*}

\end{document}
f:id:zrbabbler:20160703010002p:image

「upLaTeX の日本語」と「CJK パッケージの中国語」の両方について、フォント選択が正常に行われていることが判る。

rubyでルビしたい例

CJK パッケージがまともに使えるということは、ruby パッケージもまともに使える。ruby パッケージの \ruby 命令を用いて中国語にルビを振って、あとイロイロしてみる例を示す。

% upLaTeX 文書; 文字コードUTF-8
\documentclass[uplatex,a4paper]{jsarticle}
\usepackage[T5,T1]{fontenc}% フォントエンコーディングしたい
\usepackage{pxCJKutf8,CJKspace,CJKpunct}% CJKしたい
\usepackage[prefernoncjk]{pxcjkcat}% 欧文UTF-8直接入力したい
\usepackage{lmodern}% Latin Modern したい
\usepackage[CJK]{ruby}% 中国語でルビしたい
\usepackage{pxrubrica}% 日本語でルビしたい
\rubysetup{<->}% pxrubricaの設定
\begin{document}
% 中国語(簡体) : ruby でルビする
\begin{CJK*}{UTF8}{gbsn}
我的\ruby{气垫船}{qìdiànchuán}装满了\ruby{鳝鱼}{shànyú}\par\bigskip
\end{CJK*}

% 日本語 : pxrubrica でルビする
私のホバークラフト\jruby{}{うなぎ}でいっぱいです。
%※別の \ruby がある場合は pxrubrica の \ruby は \jruby とする.
\par\bigskip

% 韓国語
\begin{CJK}{UTF8}{nanummj}% こちらは'*'無しのCJK
내 호버크라프트는 장어로 가득 차 있어요.
\par\bigskip
\end{CJK}

% ベトナム語
{\fontencoding{T5}\selectfont % フォントエンコーディング切替
Tàu cánh ngầm của tôi đầy lươn.
\par\bigskip}

\end{document}
f:id:zrbabbler:20160703032115p:image

なお、日本語の部分(「upTeX の和文」として処理されている)に ruby パッケージの \ruby を適用することは(恐らく)可能であるが、“まともに”出力させるのは結構大変である。日本語のルビのためのパッケージを利用するのが無難である。

*1:ちなみに、CJKutf8 パッケージは「CJK パッケージと欧文の utf8 入力エンコーディングの機能を両立させるためのもの」である。

2016-06-30

pLaTeX のコードに潜在するバグを一気に消し去る話

最近、pLaTeX がますます新しくなってますますアレ、なことになっている。

長らく放置されている pLaTeX のチョットアレな点を改善していこうという取組みは基本的には好ましいと考えている。ただ今の開発者チームにおける開発体制がチョットアレなために、「チョットアレを直すと別のチョットアレが出てくる」という残念なことになっている。このような現状を打開するために、開発体制の見直しが目下進められている。

※開発方針議論に興味のある方はこちらへ:
今後の pLaTeX/upLaTeX の開発について (GitHub:texjporg/platex Issue #10)

本質的に問題なもの

確かに体制を工夫することも重要ではある。だがしかし、この「テスト(バグ出し)が困難である」という問題の裏にある、pLaTeX の“本質的な問題点”について、私は決して見過ごすべきでないと考える。

バグを入れないためには、該当部分が絡むあらゆる原稿 tex ファイルを想定してコードを書く能力が必要である。そして、それが正しいかどうかテストしなければならない。……(中略)…… 「バグがないことの証明」は悪魔の証明とも匹敵する難易度だろうと思う。

なぜテストケースを出し切れないかというと、その根本的な原因は、

pLaTeX の機能が多すぎる

からである。pLaTeX を使うと多種多様な文書が作成できる。その可能性は限りない。しかし、その多様性こそがテストを著しく困難なものにしていることは否めない事実である。

確かに、多様な文書が作成できることは一般的に好ましいと捉えられている。しかしそれは必要不可欠なものであろうか。ここで別の立場を取ることもできるのではないか。

現状の tcclearerr については
TeX文書の出力に本当に必要なもの」
に対する考察が致命的に欠けている。
本当に出力すべきものなんて、ゆきだるま☃しかないはず。
(なお、tcclearerror というのは、とある画期的な LaTeX パッケージの名前である。)

抜本的でかつ画期的な対策

もしこの考えを推進する立場に立つならば、「テストが困難」という問題に対して画期的な対策を見出せる。

入力のソースに応じて出力が変わる、という(バグの温床になる)複雑な仕様を排除して、出力を“本当に必要なもの”に限定する。すなわち、入力ソースの内容の如何に関わらず、出力は常に「ゆきだるま☃」とする、という“新しい仕様”を採用する。

すなわち、“新しい仕様”では以下のようになる。

[入力]
\documentclass[a4paper]{article}
\begin{document}
{\TeX} is great!
\[ \int x = \frac{x^2}{2} + C \]
\end{document}
[出力]
f:id:zrbabbler:20160630212831p:image
[入力]
10 INPUT A
20 INPUT B
30 C=A+B
40 PRINT C
50 END
[出力]
f:id:zrbabbler:20160630212831p:image
[入力]
ルイズ!ルイズ!ルイズ!ルイズぅぅうううわぁああああああああああああああああああああああん!!!
あぁああああ…ああ…あっあっー!あぁああああああ!!!ルイズルイズルイズぅううぁわぁああああ!!!
あぁクンカクンカ!クンカクンカ!スーハースーハー!スーハースーハー!いい匂いだなぁ…くんくん
んはぁっ!ルイズ・フランソワーズたんの桃色ブロンドの髪をクンカクンカしたいお!クンカクンカ!あぁあ!!
……(以下略)……
[出力]
f:id:zrbabbler:20160630212831p:image

この仕様を採用することで、TeX エンジンは入力のソースを全く読む必要がなくなり、それに伴い、処理の流れを完全に一本化される。結果的に、数個の入力ケースに対して正常な(仕様通りの)出力が得られることが判れば、あとはどんな入力ケースについても正常な出力が得られることの確信を持つことが可能になる。

実装

先に示した仕様に従って実装してみた。

pLaTeX カーネルに対する修正であるので、次の手順でフォーマットを再作成するのが本来の使い方となる。(初心者が誤って実行してしまうのを防ぐために敢えて不親切な書き方にしている。)

  • 先の tcsafepltx.sty を「TeX から見える場所」におく。

  • platex.ltx を以下のように編集する。
    platex.ltx 末尾]
    \let\dump\orgdump
    \let\orgdump\@undefined
    \makeatother
    \input tcsafepltx.sty % この行を追加
    \dump
    \endinput
    \endinput
    %%
    %% End of file `platex.ltx'.
    
  • pLaTeX のフォーマット(platex.fmt)を再作成する。

なお、LaTeX の初級者が簡単に“新しい仕様”を体験できるようにするため、tcsafepltx.sty は“LaTeX のパッケージとして読み込む”ことも可能なように作っている。この使い方をする場合、文書の先頭(\documentclass よりも前)において \RequirePackage 命令を用いてパッケージを読み込む。

[入力]
\RequirePackage{tcsafepltx}[] % この行を追加する!
\documentclass[a4paper]{article}
\begin{document}
{\TeX} is great!
\[ \int x = \frac{x^2}{2} + C \]
\end{document}

この場合はフォーマットの再作成は不要で、上掲の文書ソースを“普通の pLaTeX”でコンパイルすればよい。もちろん、出力は以下のようになる。

[出力]
f:id:zrbabbler:20160630212831p:image

まとめ

TeX に本当に必要なもの”に関する洞察を基にして、現状の「テストができない」問題を根本的に解決する画期的な手法提案した。この方法を取り入れるなどして「バグの無い幸せな pLaTeX」が使える日が来ることを切に願う。


ZR「なお、この tcsafepltx については、あまりにも下らないネタであるため、ロクにテストをしていない。なのでバグが残っている可能性があることを予め断っておく」
*「えっ」

2016-06-27

(u)pLaTeX で CJK パッケージする件(1)

CJK パッケージは欧文 (pdf)LaTeX で日本語(などの CJK 言語)を扱うものである。従って、元々日本語を扱うためのエンジンである (u)pLaTeX で CJK パッケージが入用になるという場合はほとんど考えられないだろう。実際には、CJK と (u)pLaTex の実装は共存できないことが知られている。

ただし、(u)pLaTeX で敢えて CJK パッケージを使おうとする話が全くない、というわけでもない。


というわけで、本記事では「(u)pLaTeX で CJK パッケージする」という話題を扱う。

(u)pLaTeX で CJK パッケージすると何がアレか

まずは、両者を併用するとどういう不具合が出るかを見てみよう。

① 和文に対するフォント変更がアレ

こちらは (u(pLaTeX の機能が異常になる、という話である。

% pLaTeX 文書, 文字コードは UTF-8
\documentclass[a4paper]{jsarticle}
\usepackage{CJK}
\begin{document}
% 和文文字に対して \Large が効かない!
{\TeX}はアレ。{\Large {\TeX}はアレ。}
\end{document}
f:id:zrbabbler:20160627001641p:image

見ての通りである。この不具合は CJK パッケージを“読み込むだけ”で発生する。詳細については次の記事を参照されたい。

この記事で触れられているように、「ruby パッケージ」にはくれぐれも注意してほしい。

中国語フォントがアレ

先の話とは反対に、こちらは CJK パッケージの機能に不具合が出る事例である。

% LaTeX 文書, 文字コードUTF-8
\documentclass[a4paper]{article}
\usepackage{CJKutf8,CJKspace,CJKpunct}
\begin{document}
\begin{CJK*}{UTF8}{gbsn}
你用中文可以写!
\end{CJK*}
\end{document}

これを pdfLaTeX でコンパイルした場合、次のような正常な出力が得られる。

f:id:zrbabbler:20160627004058p:image

一方、pLaTeXコンパイルした場合の出力はコレになる。

f:id:zrbabbler:20160627004057p:image

よく見ると、一部の漢字の字体が“日本語用”のものになってしまっている。この原因は、一部の漢字(というか、先頭の〈你〉以外全部)が pTeX エンジンにより「和文文字」として扱われて「和文用フォント」(これは通常は日本語用のフォントである)で出力されるからである。*1「和文用のフォント」を別のもの(例えば「HGS創英角ポップ体」)に変えてみるとより明確になる。

f:id:zrbabbler:20160627010824p:image

※inputenc パッケージでギリシャ文字キリル文字を出力する際に (u)pLaTeX で出力が異常になるのも同じ理由による。

和文しなくて CJK パッケージだけできればよい場合

ところで、冒頭に挙げたツイートCloud LaTeX の中の人のものである。Cloud LaTeX では現在のところ pLaTeX と XeLaTeX のみがサポートされている。*2このような状況下では、「とにかく CJK パッケージを使いたいのだが、欧文 LaTeX が使えないので他のエンジンで代用したい」というチョット特殊な要求がありえる。このようなケースについては、(残念ながら pLaTeX や XeLaTeX では厄介であるが、)upLaTeX であればかなり容易に対応できる。

欧文 LaTeX でのコンパイルを前提とした文書を upLaTeX でコンパイルしたい場合は、プレアンブルの先頭*3\disablecjktoken という命令を書けばよい。

% upLaTeX 文書, 文字コードは UTF-8
\documentclass[a4paper]{article}
\disablecjktoken % コレでOK
\usepackage{CJKutf8,CJKspace,CJKpunct}
\begin{document}
\begin{CJK*}{UTF8}{gbsn}
用 CJK 宏包和 up{\LaTeX} 可以写中文!
\end{CJK*}
\end{document}
f:id:zrbabbler:20160627020833p:image

この \disablecjktoken という命令は、和文文字の認識を無効にして欧文 LaTeX と全く同じように処理させる作用をもつ。これにより、前出の②に挙げた問題が解消される。①の現象については相変わらず残っているはずであるが、そもそも“和文文字”を用いない前提だから問題にならない。従って、ほとんどの場合に正常な出力が得られることが期待できる。*4

pLaTeX な場合は

残念ながら \disablecjktoken は upTeX エンジン特有の機能なので pLaTeX では使えない。pLaTeX で同様の処理をしたい場合は「非 ASCII 文字を TeX エスケープするテキストフィルタを適用する」といった、古典的なテクニックを駆使する必要がある。例えば、pxfltsrc パッケージ*5を利用する場合は以下のようになる。

% pLaTeX 文書, 文字コードは UTF-8; -shell-escape 指定が必要
\documentclass[a4paper]{article}
\usepackage{CJKutf8,CJKspace,CJKpunct}
\usepackage[byte]{pxfltsrc}
\filterstart % これ以降のソースの和文文字を無効化する
\filterinput % 以後に読み込まれるファイルの和文文字を無効化する
\begin{document}
\begin{CJK*}{UTF8}{gbsn}
用 CJK 宏包和 p{\LaTeX} 可以写中文!
\end{CJK*}
\end{document}

この場合、コンパイル時にシェル機能を有効にする(-shell-escape)必要がある。(だから Cloud LaTeX ではこの方法は使えない。)

※なお、Cloud LaTeX が前出の①や②の問題に関してどのような対策を施しているか(あるいはそもそも何の対策もしてなくて失敗するのか)については、自分は調査していない。

*1:非 ASCII 文字について、CJK パッケージが予定通り処理するためには、文字が「欧文扱い」であることが前提にある。

*2:upLaTeX と LuaLaTeX のサポートが(近い将来に?)予定されているようである。

*3:要するに CJK 文字が出現するより前。もし文書クラスの実装の中に CJK 文字が含まれるのであれば、\documentclass 命令の前に書く。

*4LaTeXpLaTeXカーネルの差異により、欧文 LaTeX でのコンパイル結果と全く同一にならない可能性はある。

*5:懐かしいね……。

2016-06-24

例の \selectfont のアレ

アレ。

どういう方針になるかはわからないが、取りあえずソレっぽいコードを書いてみた。