Closed t-tk closed 9 months ago
で、書いてみたコード https://github.com/texjporg/tex-jp-build/commit/02266b1e4ca3e52cd94d0be3be5944ddf78c75aa について説明します。
新しく文字コードを推測するルーチン ptenc_guess_enc()
(140行ほど)を書いた。
入出力の形式は土村さん作の ptexenc_nkf()
と大体同じ。
判定の方針は、以下の通り。
ESC $ @
またはESC $ B
)が現れたら即座にISO-2022-JPであると判定する。機種依存文字やShift_JISの半角カタカナが含まれると判定に失敗し、大体のケースで BINARY と判定されます。 機種依存文字や半角カタカナはptexencの扱うソフトウェアでは使わない原則になっているので問題ないはずです。 実用的な入力ファイルのほとんどの場合は判定に成功するはずです。 逆に半角カタカナも候補に含めると、関連ソフトで扱わないのにも関わらず判定精度を落とす結果になりそうです。
また、ファイルの先頭から合法であるかどうかを頼りに判定していきファイル全体を見ないので、ごく一部のゴミを除いて大多数が正しい文字コードであるような場合で、ゴミが最初の方に現れると誤判定する可能性があります。
で、合法な文字コードの候補が複数存在するままファイルの終端まで達する場合があります。
候補が(Shift_JISとEUC-JP), (Shift_JISとUTF-8), (EUC-JPとUTF-8)となる可能性があります。
その場合は AMBIGUOUS
と判定しつつ file_enc
を選ぶようにしています。
このため、候補が(Shift_JISとEUC-JP)なのにも関わらずUTF-8になってしまう可能性もありますが、候補が絞り込めない状態であること自体が自動判定の限界であり回避すべきことなので、これ以上頑張らないことにするつもりです。
(Shift_JISとEUC-JPとUTF-8)の3個とも候補のままになるのは半角カタカナが含まれない条件の下ではありえないようです。
文字集合の使用頻度をもとに推測する方法なども知られていますが、そこまで頑張るつもりはありません。 今の判定精度で充分と考えています。
まだ迷っている点は以下。 [1] 判定が確定するまでファイルの中を探し続ける方針のため、ASCIIのファイルで非常に長い場合判定が付かず最後まで読むことになる。 ptexencが扱うファイルの中にそういうものがありそうで、無駄にも思える。 そういう場合に判定を打ち切るよう長さ制限を設けるべきか? → ASCIIのチェックは先頭10000以内限定に変更した。 [2] TeX Live の配布物として自動判定のdefaultをオンにすべきかオフにすべきか?
[1] 判定が確定するまでファイルの中を探し続ける方針を少し変更しました。
ファイルの先頭から10000バイトの中に8bit文字が見つからない場合 ASCII と推定する。
このとき、ファイルの文字コードには file_enc
が使われる。
ファイルの先頭から10000バイト以内に8bit文字が見つかっている場合は、ファイルの最後に達するか、もしくは文字コードが一意に決まるまで判定を継続する。
ほぼ大多数の場合にこれで問題ないはず。
失敗するケースはもともと自動判定に向かないレアケースなのでこれ以上頑張らない。
[2] TeX Live の配布物として自動判定のdefaultをオンにするか否かは、[1]の方針によりデメリットが減ったためオンにしてもよいと今は考えています。
[3] 文字コードに 0x00 が含まれる場合にバイナリーと判定する手法が、git やその他多くのソフトで採用されているらしいのでこちらにも入れてみました。
mendexでも guess_input_kanji_encoding が効くようにしました。 自動判定のdefaultは、ptex, eptex, platex, pbibtex, mendex で効くようにしてみました。 テストも増やして、期待通りの動作をしているようです。 そろそろTeX Liveにコミットしてもいいかなと考えています。
色々とありがとうございます。動作確認がまだなのですが,2点コメントです。
コメントありがとうございます。
--[no-]guess-input-enc
オプションは未検討でした。
とりあえず、(u)pTeX 系列は W32TeX と同様のものが https://github.com/texjporg/tex-jp-build/commit/9c0627ae3a928bd986593ea949519c9b7f3c1c8d で入ったと思います。
kpathsearchの変数は環境変数からも渡せるので↓のようにして有効化できますが、コマンドラインオプションでも欲しいでしょうか?
$ guess_input_kanji_encoding=1 ./mendex -U -d $srcdir/tests/uni.dict -s $srcdir/tests/sjis.ist
ありがとうございます。
kpathsearchの変数は環境変数からも渡せる
それはその通りで,bash だと一行でいけますが Windows の cmd だといったん set しないといけない(export に相当)のが少し面倒でした。あとコマンドラインオプションのパース方法の恩恵(文字列最短マッチ)もあって,-no-guess-input-enc を短縮して -no-g でもいけたのは楽でした。
platex 同様に platex-dev も自動判定有効がいいです。 > texmf.cnf
mendex に --[no-]guess-input-enc
, (u)pbibtex に [-no]-guess-input-enc
を入れてみました。
mendex は文字列最短マッチではないのでオプションの文字列全部を書く必要があります。
platex-dev の自動判定は、そうですね。まだ入れていませんが入れましょう。
入力ファイルの文字コードのptexenc内部ルーチンでの自動判定について、 日本語用としてはすでに充分な内容になっていると思いますが、以下の検討を開始しました。
1について、 TeX関連のレガシーエンコーディングとして欧文では ISO-8859-1 (Latin1) であることが非常に多いが、文字コードの自動推測または自動判定をする手軽なソフトが無い。(nkfはISO-8859を対象にしていない。perl Encode.pmはちゃんと使えば使えるが少々面倒)
2について、
ptexenc での判定は nkf など外部の判定と違う部分があり、手軽に ptexenc での自動判定(nkf --guess
相当)を知りたいケースがある。
文字コード変換についても、nkf など別ソフトと違う部分があるため、ptexenc での結果を見たいケースがある。
nkf は海外の環境では用意されていない場合があり、pTeX 関連で使いたいときにnkfの代わりに使える状態にしておきたい。
まず、1についてパッチを書きました。
nkfに似た機能の文字コード変換ソフトを導入したい
について、ptekf
という名称 (仮称) の簡単なソフトを追加しました。
今のところ以下のようになっています。ご意見、ご感想などあればお願いします。
ptekf
の名称は、nkf
に似せた ptexenc kanji filter
のような意味です。
ただし、stdinからstdoutへ流すfilter の動作は想定していません。
特に、入力は stdinを想定しておらず、ファイルのみを想定しています。
汎用の漢字変換ツールの目的ではなく、あくまで ptexenc で行っている漢字変換を、テキストファイルの入出力で確認することを目的とします。
なので、ptexenc の関数をなるべくそのまま使うようにしています。
ptekf
のバイナリを TeX Live の配布に含めるつもりですが、開発やデバッグ用のつもりで、あまり凝ったことはしていません。
nkf
に似せるのも、少ししかしていません。オプション -U
, -u
は ptekf
では UTF-8 入出力に割り当てています。
UTF-8からレガシーエンコーディングに変換する際は、変換できない文字は NULL \0
になるようです。
大体、私が想定した通り動いているようです。
今のところ、内部コードは uptex
決め打ちになっています。内部コードを euc
, sjis
にすることも可能と思いますが、現在見送っています。
guess で ISO-8859 が判定できるなど、自動判定の入力の仮定やアルゴリズムは nkf
とかなり違います。
ptekf ver.20240127 (utf8.uptex) (ptexenc version 1.4.4/dev, TeX Live 2024)
Copyright (C) 2024 Japanese TeX Development Community
Usage: ptekf -[OPTION] [--] in_file1 [in_file2 ..]
j/s/e/u Specify output encoding ISO-2022-JP, Shift_JIS, EUC-JP, UTF8
J/S/E/U Specify input encoding ISO-2022-JP, Shift_JIS, EUC-JP, UTF8
G Guess the input encoding and output to stdout or files
--guess -g Guess the input encoding (no conversion)
--version -v Print version number
--help -h Print this help
--buffer -b Output internal buffer without code conversion
Default input/output encoding depends on kpathsearch parameters PTEX_KANJI_ENC, guess_input_kanji_encoding
Email bug reports to issue@texjp.org.
ptekf ですが、改行が CRLF なファイルを入力すると出力の改行が二重(LF+LF)になっている気がします。
ご報告ありがとうございます。 改行コードは触っていないつもりでしたが、変わってしまうのですね。なぜだろう? まずは調査からですね…
mfgets()
で変換してしまっていたようです。↓で手元では直ったように見えます。
diff --git a/source/texk/ptexenc/ptekf.c b/source/texk/ptexenc/ptekf.c
index 4c52009f6..e3fcdcf29 100644
--- a/source/texk/ptexenc/ptekf.c
+++ b/source/texk/ptexenc/ptekf.c
@@ -87,7 +87,7 @@ static char *mfgets(char *buff, int size, FILE *fp)
if ((len = input_line2(fp, (unsigned char *)buff, NULL, 0, size, &c)) == 0
&& c != '\r' && c != '\n') return NULL;
if (c == '\n' || c == '\r') {
- if (len+1 < size) strcat(buff+len, "\n");
+ if (len+1 < size) { buff[len]=(unsigned char)c; buff[len+1]='\0'; }
else ungetc(c, fp);
}
if (c == EOF) return NULL;
ありがとうございます。こちらでもうまく動いているようです。
最後の行が改行で終わっていない入力ファイルの場合、最後の行が出力されない問題があるようです。 これも合わせて直そうと思います。
入力ファイルの文字コードの自動判定について、以前から議論がありましたが、新たに提案します。
(案) ptexenc に新しく書き起こした自前の簡単な文字コードの自動判定のルーチンを入れる。
文字コードの自動判定のルーチンの機能の要望は根強く、 nkfの判定ルーチンをptexencで利用できるようにしたものを土村さんがお書きになっておりW32TeX に採用されていますが、 TeX Live のソースには入っておらず、現在Windowsでしか利用できない状態です。 W32TeXが開発終了になり Windows での今後も先行き不透明です。
以前、ICUの文字コード自動判定機能を入れてはどうかと私から提案しましたが、ICUが巨大で管理しづらくなる懸念のご指摘を受け廃案になっています。 nkf を TeX Live のソースに入れる案も以前からありますが、ICUほどでないものの欲しい機能の割に大きくて私は乗り気になりません。
そこで今回、ptexenc の管理下で扱える程度の小さいルーチンを書いてみました。 処理内容等については続けて投稿します。
(2024/02/21 追記) 判定の方針は少しずつ修正してきたので、備忘録を兼ねて、現行版の判定の方針を以下に記載します。
ESC $ @
またはESC $ B
)が現れたら即座にISO-2022-JPであると判定する。