pTeX を UTF-8 入力に対応させる試み(5)

UTF-8対応(4) までと機能的にはほぼ同じですが、 一段落したので情報をまとめ直します。 (が、詳細には立ち入らないので UTF-8対応(3) などもご覧下さい。) 新しい話題には [new!] の目印をつけておきます。

ptexenc ライブラリ

ptexenc は、pTeX のあちこちに出てくる文字コード変換に関するルーチンを抜き出して、 ライブラリとして独立させたものです。 pTeX などから用いるにはパッチが必要です。

アスキーさんのオリジナルの pTeX の扱える文字コードは、 JIS X 0208, EUC, SJIS の3種類です。 また、外部ファイルの文字コードと、 内部処理の文字コードの組合せに強い制約があります (→漢字コードについて)。 そこで ptexenc は、文字コードを柔軟に扱える拡張もしておきました。 特徴をまとめると以下のようになります。

共通化
いくつものツールから同じルーチンを使うので、 プログラムが短くなりました。 信頼性の確保にもつながります。
ブラックボックス化
pTeX, jbibtex, mendex のようなツール類からは、 どの文字コードを扱っているのかを区別せずに、 見通しよく処理できるようになりました。
UTF-8 対応
扱える外部文字コードに UTF-8 を加えました。
文字コードの独立
ptex コマンドの外部ファイルと内部処理の文字コードの組合せの制約を取り払いました。
ロケール対応
ターミナル出力の文字コードを、 LANG によるロケールの設定に連動するようにしました。
nkf 対応
入力ファイルの文字コードを自動判定できるよう、 nkf などのフィルタを経由してファイルを読み込めるようにしました。
内部 Unicode 化への準備
内部バッファが UTF-8 のように、 可変長になっても対応できるようにしておきました。

コンパイルオプションと環境変数

ディフォルトの文字コードは、コンパイル時に ./configure の "--with-ptexenc=UTF8" のようなオプションで指定します。 これは実行時の環境変数 PTEX_KANJI_ENC や、 コマンドへの "--kanji" オプションで上書きすることができます。

jmpost は tex コマンドや pdvitomp コマンドを下請けに呼び出しますが、 jmpost に "--kanji" オプションを指定しても、下請けに引き継がれません。 このような場合には PTEX_KANJI_ENC を用いるのが便利です。

PTEX_IN_FILTER に、フルパスのコマンドが書いてあれば、 入力ファイルをこのフィルタを経由して読み込みます。 "/usr/bin/nkf -j" などを登録すれば、入力ファイルの文字コードが何であっても 処理できるので、便利です。 [new!] なお、"--kanji" オプションを指定するとこのフィルタは働かないようにしました。

フィルタの出力する文字コードは ./configure で指定したもの、あるいは PTEX_KANJI_ENC で指定したものに 合わせておきます。 ("--kanji" オプションとの整合性はもう気にしなくて大丈夫です。) JIS にしておくと無条件に読み込めるので安全ではありますが、 UTF-8 のきわどい文字 (BOM つきや合字のあるもの)をちゃんと通すには、 受け渡しも UTF-8、しかも nkf は 2.0.7 あたりの新しいものを使う必要があります。

TeX 関連ツール一般にあてはまることですが、 環境変数に書けるものは、 $TEXMF/web2c/texmf.cnf にも書くことができます。 特に、システムのディフォルトは texmf.cnf に書くのが標準的で、 環境変数はディフォルトを上書きする場合に用いられます。 PTEX_IN_FILTER はもちろん texmf.cnf にも書けるのですが、 残念ながら PTEX_KANJI_ENC は内部処理の都合で texmf.cnf を 参照しないのでご注意下さい。

文字コード変換ぐらい自前のフィルタで変換しておけば...

PTEX_IN_FILTER や --kanji=utf8 を使わずとも、TeX ソースの文字コードぐらい、 自分でスクリプトを書いて変換すれば十分だと思っている人も多いでしょう。 しかしそれでは、ちょっと込み入った状況になるだけでかなり面倒なことになります。

  • 入力ファイルを分割していて、\input{hoge2} のようにして読み込んでいれば、 このようなファイルの文字コードも変換せねばなりません。
  • 文字コードを変更したファイルをどこに作るのがよいでしょう。
    • 元ファイルと同一ディレクトリに出力紙、元ファイルの拡張子を .tex と違うものにする
    • ファイル名は同一にしておいて、別ディレクトリに出力する

      前者ならどんな拡張子を用いるかが悩ましいですし、 後者なら読み込むファイルが \input{hoge/fuga} のように ディレクトリ付きで指定されていればややこしいことになります。

自分の手元だけで使い方を制限して、それなりに動かすことは可能でしょうが、 一般的な解決手法としては、 はやり PTEX_IN_FILTER や --kanji= の出番になると思います。

内部コードと fmt ファイル

TeX には、決まりきったスタイルファイルの読み込みを 高速化する機構があります。 スタイルファイルを読み込んだ時点で、 内部の変数の状態をファイルに書き出します。 次に起動するときにはこの書き出したファイルだけを読み込み、 スタイルファイルを読み込んだかのように動き出します。 内部の変数をダンプしたものが platex.fmt のようなファイルです。

hoge.fmt は内部の文字コードによって変化するため、 ptex-3.1.10 の場合は EUC 用と SJIS 用の2種類を生成し、 platex コマンドからはこのどちらかを用いていました。

ptetex3 では、2005年6月からこの二つの fmt を積極的に用いるため、 platex-euc, platex-sjis のようなコマンドを追加していました。 内部コード、外部ファイル共に EUC の platex-euc と、 同じく共に SJIS の platex-sjis です。

しかしながら ptexenc の拡張で、 内部と外部で文字コードを揃える必要がなくなったので、 この仕様は過剰になってきました。 実際、"platex-euc --kanji=sjis" と "platex-sjis" の動作の違いを知る人は、 ほんのわずかでしょう。

[new!] そこで、ptetex3 ではもう一度仕様を変更して、 生成する fmt は一種類のみ、platex-euc などのコマンドも廃止して、 "platex --kanji=sjis" のようにオプションで文字コードを指定して もらうことにしようと思いますしました。 (同じことをオリジナルの platex で行うと、 "--kanji=" オプションで内部コードまで変更されて、 間違った fmt を読み込むことになります。 ptexenc 拡張の platex では内部コードは変更しないようにしています。)

この変更を行うと、これまではシンボリックリンクや $TEXMF/aliases を 駆使して platex-euc と platex が同じ働きをするようにしてましたが、 これが不要になり、 $TEXMF/web2c/fmtutil.cnf の記述もシンプルになります。

なお、jmpost にも fmt がありますが、 読み込むスタイルファイルに日本語が入ってないのでしょうか、 内部コードが変わっても fmt は同一のようです。

ptex の内部文字コードによる動作の違い

platex-sjis コマンドは、SJIS のファイルをタイプセットするために 用いていた人がほとんどでしょう。 しかしながら platex-euc コマンドでも --kanji=sjis オプションを付ければ 同じことが可能になりました。 従って、platex-sjis と platex-euc の本質的な違いは、 内部処理の文字コードにあることになります。 以下では、廃止予定のした platex-sjis コマンドを、 「内部コードは SJIS で固定、扱うファイルは SJIS だけれど --kanji オプションでも変更可能な platex」という意味で用います。

"platex-euc --kanji=sjis" と "platex-sjis" の出力の違いは、 ほんのわずかですが存在します。 ですからアスキーさんも動作を統一させられないのでしょう。 これとは対照的に、jbibtex や mendex の内部動作は元々 EUC の一通りですし、 jmpost などのツールは内部動作がどちらでも出力結果は同一のはずです。 問題があるのは ptex コマンドだけであろうと思います。

ptetex3 では fmt、つまりは platex の内部コードを(以前の pTeX のように) 一種類のみにしようとしていますしたので、 違いをまとめておきます。

hyperref を用いた PDF の日本語しおり

hyperref を用いると、生成される DVI が内部コードによって異なります。 dvipdfmx で PDF を作る場合には、この違いを吸収するために "pdf:tounicode EUC-UCS2" のような記述が必要です。 (→ps2pdf/dvipdfmx で日本語 PDF を作る) "platex-euc --kanji=sjis" なら EUC-UCS2、 "platex-sjis" なら 90ms-RKSJ-UCS2 を書きます。

ここに書く文字コードには誤解が多いので強調しておきます。 外部ファイルの文字コードを書くべきだとお思いの方が多いでしょうが、 実は内部コードを書きます。 それが証拠に platex-utf8 でも EUC-UCS2 と書きます。

以下のように、自動判定させている場合は常に正しく動きます。

\usepackage[dvipdfm,bookmarks=true,bookmarksnumbered=true,%
bookmarkstype=toc]{hyperref}
\ifnum 42146=\euc"A4A2
\AtBeginDvi{\special{pdf:tounicode EUC-UCS2}}\else
\AtBeginDvi{\special{pdf:tounicode 90ms-RKSJ-UCS2}}\fi

ちなみに、dvips + ps2pdf で PDF を作るならば、むしろ話は単純です。 PS を ps2pdf に通す前に、松本隆太郎氏の hyperrefと日本語 の convert-euc.txt のようなものを用いることになるでしょうが、 こちらは platex-euc であれば --kanji にかかわらず EUC 動作をさせればよいです。 ソースに細工をしておく必要はありません。

文字集合の範囲

アスキーさんが意図されているかどうかは不明ですが、 ptex は 内部 SJIS のほうが多くの文字集合を扱えます。 数は少ないながらもこれを利用したパッケージがあります。 (→JIS X 0213への道

この恩恵にあずかるためには、 もちろん ptex の内部コードを SJIS にしておく必要がありますが、 普段の入出力は EUC のほうが便利という場面も多いでしょう。 そのためには ./configure 時に SJIS を指定し、 環境変数 PTEX_KANJI_ENC に EUC をセットしておけばよいです。 もちろん、広い文字集合の入ったファイルは SJIS で書いておき、 "platex --kanji=sjis" でタイプセットしなければなりません。

こうした場合、nkf との併用でうまく処理できるかどうかは自信がありません。 また当然ながら、はみ出した文字は jbibtex や mendex では扱えません。

カテゴリコード表の統一

[new!] 通常のユーザには不要な情報で、 直接は ptexenc とも関係のない話題ですが、 ptex 用のパッチの中で実現したことなので、ここに書いておくことにします。

ptex 内部に、カテゴリコード(文字の属性)を決めるテーブルがありますが、 内部コードに応じて、EUC 用と SJIS 用の2種類が存在します。 つまり、2つのテーブルを同じ動きになるよう注意深く作ってあるというわけです。

2つのテーブルの存在は、そうそう中身を変更するものでもないため、 特にこれまで問題になることもなかったようです。 しかしながら、ptexenc により内部コードによる場合分けがほとんど消滅したため、 このテーブル作成ルーチンが最後に残った大きな場合分け処理となりました。 アスキーさんの解説 にも「2バイト文字のカテゴリコードを変更することはできません。」 とあり、EUC と SJIS での動作の違いが制約になっているように思えます。 (もっともユーザレベルでこのテーブルを変更する場面はほとんどないはずですが。)

気になっていたところに ttk 氏が upTeX でテーブルを統一した実装を公開されたので、 ほぼそのまま取り込ませていただきました。 ただし、ある意味で以前との互換性を失う改造であるのも事実です。 テーブルを変更している数少ないマクロ(前述の JIS X 0213への道 が該当)は、動かなくなっていると思われます。 また、fmt は生成しなおす必要があります。 [qa:47726] もご覧下さい。

UTF-8 対応の意味

ここでの UTF-8 対応は、 過去との互換性を最大限に確保することを目標としています。 つまり、EUC や SJIS で書かれたソースを UTF-8 に変換しても、 まったく同じ出力が得られることを目指しています。 UTF-8 テキストでは、直接表記できる文字集合が増えましたが、 直接のサポートは行いません。

このため、多言語処理のために

\usepackage[utf8]{inputenc}

を用いる場合に、例えば latex で処理すれば \textsection と等価になる「§」が、 platex --kanji=utf8 では全角文字となってしまいます。 これはこれで避けようがないと思います。 最近気づいたのですが、pTeX に「\西暦」のマクロが存在するように、 「\α」というマクロも定義できてしまいます。 こういうものの互換性を確保するには、 やはりキリル文字も全角として扱うしかないであろうと思います。

ところで、UTF/OTF パッケージと inputenc を組み合わせると、 JIS 第1,2水準にない文字を直接表記することも不可能ではありません。 発案しておきながらも、うまい方法とは思ってなくて、 XeTeX や upTeX のようなちゃんとした Unicode 処理のできるものが よいと思っています。

普及状況

一連の UTF-8 対応は、ptetex3 だけでなく、 既に角藤氏の W32TeX にも採用されています。 Vine Linux 4.0/4.1 の TeX も、ptetex3 がベースになっているので、 当然のように UTF-8 対応が入っています。 (ライブラリ化する前の初期のものですが。) [改訂第4版]LaTeX2e 美文書作成入門 でも大きく取り上げていただきました。 それなりに普及してきていると思います。

ptexenc は kpathsea から独立させたため、 例えば TeX Live で用いることも簡単になったと思います。 dvips/xdvi などの DVI ware からも ptexenc を使って欲しいと思っているのですが、 これにはもうしばらく時間がかかりそうです。

ご意見をどうぞ

  • いつもお世話になります。xdviは巨大なunicode表を含んでいるのでptexenc化のメリットは大きいと思いますが、dvipsはJIS→SJISの変換の簡単な関数(upTeX版はさらにサロゲートの計算)を含んでいるだけですのでメリットはわずかだ思います(わずかでもメリットはメリットですが)。 -- ttk 2007-04-29 (日) 07:32:24
  • いつもありがとうございます。dvips でももう少しぐらい ptexenc の利用価値があるかと漠然と思っていたのですが、そうでもなさそうですね。 -- 土村 2007-04-30 (月) 19:02:06
  • (公開されるときには分かることかもしれませんが...)「nkf 対応」では,具体的にはどんなフィルタをシステム側に用意しておく必要があるのでしょうか? それとも ptetex3 ソースに同梱の予定でしょうか. -- kuroky 2007-04-30 (月) 18:13:42
  • すいませんが、質問の意図が汲み取れずにいます。 UTF-8対応(3)#z1df24aa では情報が不足しているという意味でしょうか。 それとも nkf-2.0.7 を同梱して欲しいというリクエストでしょうか。 後者は考えないでもないですが、実績も少ないので、現時点ではそこまで押しつけるのはどうかと思っています。 ちなみに、拙作 RPM では nkf を使うようにしているものもあります。 -- 土村 2007-04-30 (月) 19:12:29
  • UTF-8対応(3) の記述まで頭が回っておりませんでした + 「コンパイルオプションと環境変数」の説明に自分の頭が付いていっていなかったです.リンク先を読んで,理解できてきました.
    もとの意図は,nkf「など」が気になったのと,nkf のないシステムではどうするのだろうという疑問から来るものでした. -- kuroky 2007-04-30 (月) 23:50:26
    • ↑のコメントを後から見に来た人への回答: フィルタを登録していないシステムで (追記: --kanji= 指定をしないとき) は,外部コードは,ptex を make したときに指定する文字コード (= 内部コード) と同一だと思って処理される (hyperref で作られるしおり情報も内部コードと同一になる) ということのようです.-- kuroky 2007-05-01 (火) 22:21:23
  • 上項に関する質問があります。"configure sjis" で "ptex --kanji=euc" の場合は、漢字コード変換が行われるはずですが、これは「ユーザがnkf(等)使用を指定できるが、そうでなければ自前ルーチンで行う」のでしょうか。 -- ZR 2007-05-02 (水) 14:24:51
  • 内部コードは sjis、ファイルは euc として扱われます。コード変換が必要なときは、 ptexenc が行います。 --kanji オプションを指定した場合は、 フィルタ (nkf 等) は無効となります。 -- kakuto 2007-05-02 (水) 22:15:55
  • 角藤氏にお答えいただいた通りです。 このページには大きな話題をピックアップしてみました。 詳細は(若干古い情報も混じってて恐縮ですが)昔のページを参照いただければありがたいです。 というわけで、nkf 対応に関する話題は UTF-8対応(3)#z1df24aa で議論させていただければと思います。 -- 土村 2007-05-03 (木) 00:37:29
    • 昔読んだ内容の一部を失念していました。失礼しました。 -- ZR 2007-05-03 (木) 13:17:54
  • 以前の書き込みの一部を check_kanjiとkcatcodeの範囲チェック#yd5083c3 に移動しました。 -- 土村 2007-05-13 (日) 02:07:50
  • 文中の「一連の」の部分なのですが,「この UTF-8 対応(5) 等の方法(による UTF-8 対応)は、ptetex3 だけでなく、 既に角藤氏の W32TeX にも採用されています。」という意味に受け取りましたが正解でしょうか? -- kd 2007-07-14 (土) 17:40:22
  • W32TeXのChangeLogによると、現在、PTEXENC 0.96(ただしPTEX_IN_FILTERは無効) となっているようです。 -- ttk 2007-07-14 (土) 20:42:03


トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2007-12-07 (金) 14:11:11 (5977d)