From: "NARUSE, Yui" Date: 2010-11-03T02:41:35+09:00 Subject: [ruby-dev:42517] Re: [Ruby 1.9-Bug#3990][Closed] tests of rexml/rss reports many errors and failures without iconv 成瀬です。 まず、用語を整理すると、 iconv: ext/iconv のこと、文字コード変換器 glibc iconv とか GNU libiconv とか Citrus iconv とかを呼ぶ transcode: transcode.c と enc/trans/* あたりで実装され、 String#encode とかで使われる物 Encoding: encoding.c や enc/* で実装され、Encoding クラスとして現れたり、 String や正規表現の裏で文字を操る。 (2010/11/02 23:38), Kouhei Sutou wrote: > えーと、もともとiconvの代わりにEncodingをという話から始まって > いたのでEncodingを使っていたのですが、使い分けた方がよいので > しょうか? というわけで、ここは「iconv の代わりに transcode を」です。 > 使い分けたとして、transcodeがiconvの代替として使うにはまだ早 > いということであれば今回の変更は時期尚早だった気がします。 これは問題ないと思います。 >> それぞれのエンコーディングの実際上の射程範囲は文脈によって代わります。 >> そして、HTTP や HTML、XML などのエンコーディングと、Ruby M17N の >> エンコーディングは一部射程範囲が異なります。 > > 今はXMLだけ考えています。 後述の通り、事情は同じです。 > 具体的にはどこが異なるのでしょうか。 > > 私の認識は以下の通りです。 > > * XMLのエンコーディングはIANAに登録されているchaset名をベース > にしている。x-はじまりのものなども使えまるが、REXMLでは > サポート対象外。 建前はそうです。 しかし、現実問題としては ISO-8859-1 と称しつつ中身は Windows-1252 だったりします。 (例えば未使用であるはずの 0x80 がなぜか使われていて、それがユーロ記号を期待している) 日本で言えば円記号問題や波ダッシュ問題がそうですな。 歴史的経緯を説明すると、当初の IANA Charsets は情報交換用符号の名前登録簿だったので、 その内容について詳細な合意は取られていませんでした。 charset という名前自体が、符号化文字集合と文字符号化方式が分化する前のもの であることを物語っているとも言えます。 ISO-8859-1 と Windows-1252 の違いや、EUC-JP が含む補助漢字を CP51932 が含まない こともこの辺の一環でしょう。 で、現実はと言えば、インターネット上においてほとんどのデータは Windows ベースの ものとなっています。また、Windows のデファクト化につられてインターネット関連の ソフトウェアは Windows の定義にあわせるようになりつつあります。 また、Unicode 登場時に既存の文字コードとの変換表を統一することに失敗した事も 乖離を増大させています。日本においては波ダッシュ問題がそれです。 こちらも、変換表を Windows にあわせることになりつつあります。 以上をまとめると、「IANA Charsets における名前とその正式な定義」と、 Windows 由来のデファクトは乖離している、と言うことになります。 具体的にどの charset が乖離し、その実態は何なのかは HTML5 の人々がまとめています。 http://www.w3.org/TR/html5/parsing.html#character-encodings-0 で、REXML の扱う XML データがインターネット上のデータ同様に正式な定義から乖離しているか、 が一つの論点ですが、REXML の主たる用途が RSS で、RSS のデータ元が blog 等の Web 媒体で、 それらが元々は Web ブラウザ経由で入力されているであろう事を考えると、 上述の状況と同じなんじゃないですかね。 > * RubyのEncodingもIANAをベースにしている。 「ベースにしている」は正しいんですが、Ruby では IANA のある名称の実装には、 正式な定義を一致させ、デファクトに対しては Windows 由来の名前を与えています。 例えば、ISO-8859-1 と Windows-1252、Shift_JIS と Windows-31J、 EUC-JP と CP51932 などです。 なので、一連の名称群の空間は一致していますが、意味づけにずれがあります。 そもそも論を申しますと、この違いは情報交換用符号と内部処理用符号の違いだったりします。 > なので、REXMLで使う範囲では十分カバーしていると認識しています。 というわけで、概ね範囲としてはカバーされているのですが、意味論が違うわけです。 カバーしきれてない例を挙げると、例えば UTF-16 とかですか。 もっとも、ここで述べた違いを REXML でまともに扱うかはまた別の話です。 > ただ、これはiconvを利用している場合でiconvがない場合はBOMな > しになっていたはずです。 > > # 今のままでもBOMをつけるくらい簡単なので、必要であればつけて > # しまってもいいとは思っています。 BOM をつける場合は encoding は UTF-16 でなければいけません。 一方で、UTF-16BE を名乗るならばそれに BOM をつけてはいけません。 >> これの結果は、現在以下の通りになってしまっています。 >> => "" > > このように表示されるのは適切にencodingが設定するようになった > からだと思っています。trunkだとちゃんとUTF-16BEが設定されてい > て(なので\xXXにならないで表示される)、以前は(UTF-16なの > に)UTF-8が設定されていたと思います。 表示結果に関しては確かにご指摘の通りです。 これで、encoding='UTF-16BE' ならばこの結果単体は問題ありませんね。 >> これによって、少なくとも XMLDecl#encoding の戻り値の意味は、 >> XML 宣言の encoding 属性で用いられる値であって、内容の Ruby の文脈における >> encoding とは異なる物であるといえるのではないでしょうか。 > > すみません、「内容の Ruby の文脈における encoding」が何を指し > ているのかが分かりませんでした。テキストのencodingとか、そう > いう意味ですか? 具体例ですと例えば、 ''.encode("Windows-31") とか。ここでの「内容の Ruby の文脈における encoding」は Windows-31J です。 > そうだとして、異なる場合はどうした方がよいと > いうことでしょうか。 XMLDec#encoding は文字列にして、XML 宣言に入っているものを そのまま使うべきです。 > ちなみに、「XMLDecl#encoding の戻り値の意味は、」XMLとして文 > 字列化したときに使われるencodingでもあります。まとめると、今 > はこうなっていると思っています。 > > * REXMLのオブジェクトを作るときのencodingはXML宣言で指定 > * REXMLのオブジェクトを操作するときの入出力はUTF-8 > * REXMLのオブジェクトをXMLとして出力する時はXMLDecl#encoding 「XMLとして文字列化したときに使われるencoding」が上述の、 「内容の Ruby の文脈における encoding」です。 で、これは XMLDecl#encoding とは分離する必要があります(長期的には)。 そこまでやらない場合は XMLDecl#encoding 側に 「XMLとして文字列化したときに使われるencoding」をあわせるべきです。 これは言い換えると、 * 情報交換用符号側に内部処理用符号をあわせるべき * XML の公称しているエンコーディング名にあわせるべき * Ruby の Encoding オブジェクトでなく、エンコーディング名を文字列のまま使うべき などとなります。 >> そもそも、UTF-16 の場合 UTF-8 に変換して扱うし。 > > UTF-16以外の場合でもREXML内部では常にUTF-8で扱っています。 仰るとおりです。 >>>> というわけで、encoding メソッドは以前のままにして、Encoding オブジェクトを >>>> 返すメソッドを新設した方がよいのではないかと思います。 >>> >>> encodingよりもEncodingオブジェクトを返すのに適切な名前を思い >>> つけないので、そういうAPIにはしない方がよいと思っています。 >> >> Encoding オブジェクトバージョンの名前をどうするか、というのは、 >> それはそれで難しいのですが、上述の理由からそうせざるをえないと思います。 >> 私案では string の encoding なので str_encoding かなぁ。 > > うーん、上述の理由を受け入れられないのは別としても、その名前 > は受け入れられないです。適切でない場所にはみ出してしまった感 > じがします。 Encoding オブジェクトバージョンが必要なのは、上述の REXML オブジェクトからXMLソース文字列に変換する際に用いるエンコーディングを、 XML 宣言の encoding 属性の値とは別に持ち続けたい場合の話なので、 冒頭に述べた IANA Charsets の定義と Ruby の各エンコーディングの定義の違いを 置いておくのであれば不要ですね。 また、XML ソースに変換する際に別に与えるという方法もあります。 -- NARUSE, Yui