手元のcalkiがUTF-8の「》」相当の文字(U+8BB)を含むエントリが文字化けするので、 nkf-utf8のソースを見てみた。 どうも自動判定の優先順位がEUC-JP,SJIS,JIS,UTF-8で固定されていて、 EUCの範囲内に収まる文字列はすべてEUC-JPとみなすことになっている。 で、UTF-8の「》」はEUC-JPの「損」と同じバイト列なのだ。
どうしたものかなあ。入力の文字コードははっきり分からないので ある種の判別と変換は避けられないしなあ。
今後、M17Nを取り込むにあたって もっと賢い自動判別がは必要だろうなあ。自動判別は正しくない判断をする 可能性があるから、なるたけ避けたいと言っても、実用のためには 避けて通れないだろう。
優秀なコード判別アルゴリズムはあるのかな。 Emacsのコード判別は結構賢いな。 上記の「》」と「損」も区別できてるし。
判定論理の賢さというより、使用テキストのコード種比率の変化に対応なのでは、nkfを使うときに 多いほうに判定しておくと、賢く見える。(Vistaで拡張した漢字を使うには UNICODE が必要。)
えーっと、U+00BB Right-Pointing Double Angle Quotation Mark "\xC2\xBB" ですよね? nkf 的には現在の動作で「正解」だと思います。U+00BB なんかはまだ日本語文でも出てきそうですが、U+00B7 Middle Dot vs 揃 だとか、U+00B8 Cedilla vs 存、U+00BA Masculine Ordinal Indicator vs 尊 などの例を考えればUTF-8が正解とは言えないはずです。。なお、一文字でEUCやSJISとUTF-8が被る範囲は U+0080-U+07FF が考えられここにはラテンギリシャキリル等々の文字が収められているわけですが、一方のEUCはJIS第一水準等、どちらをnkfが優先するべきかは明らかかと思います。もっとも、複数文字からなる文字列で、U+BBが入っているだけで誤判定するならばバグだと言えるので、その場合は話が別ですが。
ちなみに、いわゆる半角カナのSJIS「ネコ」とEUCの「蛤」も同じ "\xC8\xBA" になりますが、これもEUCに倒しておいた方が妥当であろうという判断をしています。その他、判断つかないパターンをいくつか検討した結果、どのようなケースでもEUC>SJIS>JIS>UTF-8の優先順位が一番妥当な結論を導けるという判断に至り、現在のようになっています。(Shift_JIS-2004とUTF-8ではUTF-8とした方が妥当と思われるケースがあるが、Shift_JIS-2004は自動判定の対象外)
なお、Emacsは片っ端からiconvにつっこんで、最初にエラーの出なかったものでFAを出すという仕様だった様に記憶しています。
あるべき論になると、弾さんの仰るとおり、わからんものはわからんと返すべきでしょう。encodingを候補として渡し、iconvにつっこんでvalidなもののリストを返すあたりに落ち着きそうな気がします。それ以外の方法はある条件下で精度がいいように見えても、それはたまたまおいている暗黙の過程がテストと相性がよかっただけ、の可能性が高いかと。
蛇足ながらcalkiに関して申しますと、入力のエンコーディングはわかっているのだから自動判別にせずに明示的に指定すべき、の一言です。今は亡きBSDマガジンに弾さんが書いていましたが「Guessは下衆なもの」なわけで、そんなものに無闇に頼るべきではありません。
エントリに書いたことだけでは伝わらなかったかもしれませんが、変換しようとしたものは「損」一文字ではなくて、英語の文章に「》」が含まれたものです。なんか英文ブログのタイトルによく「》」って使われてるんですよね。
で、別に無茶を要求してるわけではなくて
* コード推定の優先順位を指定したい
* 推定候補が複数ある時にはそれらを知る方法が欲しい
ってことなんだと思います。エントリを書いた時点では自分でもよく分かってなかったんだけど。
で、最後に入力のエンコーディングについてだけど、form/x-url-encodingでPOSTされた文字列のエンコーディング情報って、どうやって得るんでしょうね。ブラウザから来る情報にcharset指定とかついてないですし。素人臭い質問で申し訳ないけど、ほんとに素人なんで。
一応英文かなーとも思っていましたが、英文の中に漢字だけでもまだ弱いかなという感はありますね。EUC「大量のASCII+漢字 ひらがな無」 vs UTF-8「大量のASCII+記号」だと英文であろうとみなして後者かなぁとも思いますが、タイトルのように数十文字程度だと「英文」とみなせないだろうなぁ・・・。
優先順位の指定ですが実際に使ってみると、UTF-8のblogのタイトルとEUCなtDiaryのタイトルどちらを優先するか等で思ったよりも機能しないケースが多い気はします。U+00BBのようなケースを別途のコードで特別扱いした方が機能するかなと。
候補複数はどうなんでしょうね。NKFでも一応可能にはなっていますが、APIをどうつっこむか悩んで結局手付かずになってます。
form/x-url-encodingでPOSTされた文字列のエンコーディング情報は、送信のcontent-typeに書いてあることもあります・・・が、多くの場合はないです。
ただ、多くの場合その文字列を送ってくるフォームのあるHTMLのエンコーディングは知っており、ブラウザは多くの場いい、そのHTMLのエンコーディングで送信してきます。つまり、受け取るデータ自体にはエンコーディング情報がなくても、たいていはエンコーディングはわかっている、と。
普通のフォームならエンコーディングが分かっているで済むのですが、今回問題にしているのはブックマークレットなので、元のページのエンコーディングがなにかを知る方法はなさそうです。
せめてUTF-8優先のguessができると良いのですが。
iconvで明示的に変換するしかないのかな。
Firefoxではdocument.characterSet、IEではdocument.charsetで文字コード名が取れるようです。これをブックマークレットのソースに仕込んでおくというのはどうでしょうか。
Gimiteさん、
情報ありがとうございます。
いただいた情報をもとにcalkiをハックしました。
なんとかなっているようです。感謝。
ブックマークレットならばタイトルを encodeURIComponent(document.title) で渡すようにすれば URL encoding された UTF-8 文字列として決め打ちできるので、それを使う方法もありますかね。
なお、優先順位と不確定時のAPIは検討課題にしておきます。技術的な理由はないので、デザインですかねぇ。あと、NKF.guessがすでにあるので名前をどうするかが最大の問題かもしれません。
あと、エントリを判定できなかったケースってU+00BBだけですか?他のケースもあれば教えていただきたいです。また、U+00BBの場合の具体例をいくつかいただけると、何かしらあがく余地が見つかるかもしれません。