charset最小化

文字コードの識別

[31] 文字コード識別する名前の体系には色々なものがあります。

識別子の体系

[24] 各種のプロトコル文書形式プログラミング言語文字コードの変換の実装などでそれぞれ文字コード識別子の体系を定めています。

[1] 文字コード名の体系
[27] この他に、 UTF-8 であることのみを示せるプロトコル要素などもあったりします。

[25] 歴史的に見ればインターネットでは IANA charset の影響力がかなり強いものの、 それ単独で用いるほどカバー範囲と定義の厳密性はなく、 各種の実装はそれを取り込みつつ各分野の従来の慣習と統合する形を採っており、 似て非なる体系が大量に生じています。


[20] 数値符号を除けば、ASCII文字で構成されるものが多いです。

[21] 稀に非ASCII文字が使われるものもあります。 文字コードの指定がなされる場面で非ASCII文字は安全に使えないことが多いので、 矛盾した状況にも思えますが、稀とはいえ現に存在します。 とはいえ多くは仕様上認められていない利用方法です。

[22] ASCII文字の諸記号は、どれを使えるか制限されていることもありますが、 守られていない場合もあります。 どれが使われるかは慣習によるところが大きいですが、 一貫しないものや体系によって違うものも多く、 統一的な基準は無いと考えて構いません。 無視したり統一したりする実装もありますが、 それによって名前が衝突する場合もあります。

[23] 大文字と小文字は、区別しないことが多いです。 正規形が定義されていることもありますが、まず意味がないと考えて間違いありません。 実態としても様々な形で使われており、 文脈と個別の文字コード次第でどの書き方が多いという傾向は多少あれども、 強い慣習といえるものはありません。


[16] 似た構造の文字コードに統一的な名称を与えようとした試みもありますが、 他の色々な名前が混在する中で統一的な命名規則を徹底するのは難しいようです。

[17] charset-editioncharset-extension のように識別子を多次元化する試みもありましたが、成功していません。


[30] 多くの文字コードは正式な唯一の名前が無かったり、 機械的な識別子としての利用に適した名前では無かったり、 人間向けと機械向けで違う名前を用意していたり、 識別子の体系によって違う名前を与えられていたりします。

[7] また、識別子の体系の管理が破綻していて、 正式な定義と実際に使われるものと違いが生じていたり、 正式な定義がないまま事実上の標準となるものが使われていたりすることもままあります。

[8] 他の識別子の体系の識別子が移入されて使われることも多いのですが、 丸々同じものを採用せずにつまみ食い + 独自分、というパターンが非常に多いので、 利用者の正確な理解を妨げています。

[6] たまに識別子に含まれる些細な記号空白の違いで「この文字コードをこれこれというのは誤りで、 これこれというのが正しい」と主張する人が出現しますが、 そのような主張は正しくないことが多いです。 「これこれの場面ではこれこれの名前が正しい」 のような限定的な条件でしか成立しないことを、勝手に拡大解釈するタイプです。

[10] より深刻な問題として、識別子が文字コード体系の細かなバリエーションのどれを指しているのか明らかでない場合や、 正式な定義と世間の実態が乖離している場合が多くあります。 識別子の体系が細かなバリエーションを区別しているのに、 実態としては混用されているような場合もあります。

[9] こうした問題は解決しないまま UTF-8 への移行が進み、表立ってトラブルにつながることが少なくなったのはいいことですが、 一方で問題の発生数が減って見えにくくなったり、 古いデータやプログラムの理解に問題があるのを修正されないままとなっていたり、 トラブル解決のための情報が減少していたりと、 狭く深い問題に変化しつつあります。

[15] フォント依存符号化のようにフォント名が事実上の文字コードの識別子となる場合もあります。

識別される「文字コード」

[12] BOM 有無など出力時の動作オプションに当たるものが文字コード名に取り込まれていることがあります。

[11] 狭義の文字コードの体系の他に、改行文字の種別や Unicode正規化の適用などの動作オプション文字コード名に取り込まれていることがあります。

[13] Base64 など内容転送符号化符号化語 escape のような文書形式プロトコルの構文、あるいはそれと狭義の文字コードとの組合せも 「文字コード」として名前が付与されていることがあります。

[28] 照合順序との組合せに名前が付与されていることがあります。

[14] 文字コードの自動判定も1つの「文字コード」として名前が与えられていることがあります。 判定法の違いにもそれぞれ名前が与えられていることがあります。

[26] 単独で用いられる文字コードの他、エスケープシーケンスで切り替えられる符号化文字集合フォントの記述に用いられる符号化など、 狭義の文字コードの体系といえるものの中にも性質が異なるものが混在しており、 識別子の体系はそれらを区別したりしなかったりしています。

[18] x-user-defined, replacement, x-transparent, default Vimにおける文字コード , prc Vimにおける文字コード , japan Vimにおける文字コード , raw-text, no-conversion, ASCII-8BIT, undecided, prefer-utf-8, unknown-8bit のように特殊な「文字コード」もあります。

[19] 特殊な「文字コード」は特定の場面で認識され、特定の場面では認識されないなど、 扱いが通常の文字コードと違うことがよくあります。

最適な文字コードの選定

[32] 文字コードの識別子を付けてデータを送出する実装は、 選んだ文字コードの名前をそのまま書くのかどうか判断を迫られる場合があります。 文字コードの選択と連動することもあれば、独立している場合もあります。

[33] ある文字コードが別の文字コード部分集合 (サブセット) 、という関係性が成立する組合せが多数あります。 ある文字コードと別の文字コードは全体としては互換性がないものの、 一部のビット組合せの割当は共通しているので、その範囲内ならどちらとしても解釈できる、 という組合せもいくつもあります。

[36] MIME最小公倍数を選ぶように求めています (>>145)。 しかし具体的にどう選ぶべきかは決めておらず、実装に丸投げしています。

[37] MIME charset US-ASCII よりも IANA charset ISO_646.basic:1983 の方が更に部分集合ですが、 可能ならこれを使うべきなのかどうか定かではありません。

[38] 実際上は US-ASCII とするべきと考えられますが、 明文規定上そう考えるべき理由は無さそうに思われます。

[39] 当時も今も、このような扱いづらい規定を厳密に適用している実装はさほど多くありません。

charset 最小化

[145] 一般に MIME の生成ソフトウェアは、 charset に可能な限り「最小公倍数」 たる文字集合を使うべきです >>265 (charset最小化)。

[146] 例えば ISO-8859-X左半分しか使わないなら、 US-ASCII を使うべきです >>265

[147] しかし現在となってはむしろ常に UTF-8 を使う方が相互運用性は高いかもしれません。

[102] MIME では未知の text/* MIME型text/plain として扱うことになっています。 charset 引数がこの際どう扱われるかは不明です。

[2] MIME charset の最小化規則と、 HTTP CGI のような動的生成って本質的に相容れないもののような気がしませんかね。あるいは streaming 的なものとも。 chunked符号化の尾っぽ header を使えば何とかならなくもない気もするけど, クライアント側で届いたところからレンダリングが不能になって結局意味がない (サーバー側でデータ生成完了後に charset を判定して一気に送りつけるのと変わらない) し、よって steraming には使いようがないし。

  • [3] >>2 の解法は最小化規則をあきらめちゃうしかないのかな。 CGI 動的生成はまだ最大の範囲を知ってそうなものだけど、 streaming だと知らないこともあり得る (多言語会談とか?) から、考えうる最大の charset (UTF-8 とか?) を予め仮定しておくしかなさそう。
  • [4] >>3 の考え方はつまり charset 指定の最大化であって、 MIME の考えとは全く逆になってしまう。
  • [5] >>4 そもそも MIME の最小化規則は相互通信性最大化を目的としている。 SMTP/822 では基本的にやり直しが効かないから、一度で相手に伝える必要がある (概念上は)。一方 HTTP とかだと内容折衝もあるし、 (歴史的経緯のせいで) ブラウザの利用者の操作で文字コード選択が出来るから (メイラにもあるけど、 MIME の思想的には考慮外だと思う。) 一度で伝える必要性ってのはあんまりないのかもしれない。こういう考え方の違いがにじみ出てる気がする。

[40] MIME の当該規定は、 ISO/IEC 8859 規格群が使われている欧米諸国でも英文は通じるようにというくらいのニュアンスで作られたものと思われます。

[41] その他に東アジアの各社の独自外字が追加された文字コードを使っていても、 標準の文字だけなら標準の文字コードを名乗るべきだとする仕様上の根拠としても使えるものです。

[42] ところが現実には欧米でも東アジアでも、市場で優位な外字を使った文字コードが標準の IANA charset を名乗るという現象が起こりました。

[43] 例えば ISO-8859-1windows-1252 の意味で使われ、 Shift_JISwindows-31j の意味で使われています。

[44] 市場で普及した実装には文字コードの識別子を厳密に使い分けるという意識がなく、 市場で広まっている識別子で当該文字コードに近いものを選べば概ね正しく解釈してもらえる (自社製品なら完全に正しく解釈できるからなおよし) というくらいの気持ちだったのでしょう。

[45] 厳密に判断する実装は実装コストと処理速度に響きますし、 市場の他の実装で未対応の文字コードとして完全に開けなくなるリスクより、 一部文字化けしたとしてもおおむね読み取れるメリットの方が大きいと考えたのでしょう。

[46] 本来なら IETF がこうした傾向が見えた時点で何らかの技術的対応を行うべきだったのでしょうが、 IETF は完全無視して放置したため、混乱が続き、たまたま選んだ製品の違いによって他の製品の利用者を攻撃するような人も出てくるような始末でした。 IANA charset

文字コードの判定における選定

[47] 文字コードの判定の処理では、判定結果を返すために何らかの既知の文字コードを選ぶ必要があります。

[48] 判定対象のバイト列によっては、該当する文字コードがいくつも存在することがあります。 (ここで問題とするのは、候補を絞り込めないときではなく、 バイト列がそれらの共通部分しか使っていないときです。)

[49] 判定器には3つの選択肢があります。

  • [51] どれも等しく候補なのですから、すべてをリストとして返します。
  • [50] 文字コードの判定の結果は復号に使われます。復号はどの文字コードを使っても同じ結果になるのですから、 どれを判定結果として返すかは成り行きで構いません。
  • [52] 復号にとってはどれも同じでも、それ以外の用途で結果が変わってくることがありますから、 できるだけ適した文字コードを選びます。

[53] >>52 は、例えば HTMLにおける文字コードの判定の場合、結果は文書の文字符号化として参照可能になります。 document.charset でアクセス可能ですし、 フォームの提出があればその文字コードフォームデータが送出されます。

[54] >>53 に対しては反論もあるでしょう。もしそのような処理にとって重要なら、 文字コードの指定が省略されているはずがありません。 それがなく判定器の推定に頼らざるを得ないという時点で、そうした処理が入っていないか、 あっても長らく機能しない状態で放置されているに違いありません。 従って、わざわざ苦労してどれかを選ぶ必要はありません。

[56] 見落とされがちで >>53 で意外と重要なのは、文字コードに依存したフォントの選択かもしれません。 明示的な言語情報が存在しない場合、文字コードによってフォントが変わって表示される場合があります。 フォントの選択

[57] 同じような英文でも ISO-8859-1欧文フォントで表示されるか、 Shift_JIS和文フォントで表示されるかで意外と雰囲気がかわります。

[58] メールを読み進めると記事ごとに意味もなくフォントが変わる、 というのは読者にとってあまり快適ではない体験です。

[55] >>52 を実装するとしたら、例えばロケール等による文字コード判定の補助のような手法が適用できそうです。 文字コードの判定

文脈

文字コードの指定, 文字コードの判定

関連

文字コードの変換

メモ

[29] GNU gettext - Bugs: bug #50357, xgettext doesn't recognise... [Savannah] (Copyright 2016 Free Software Foundation, Inc. Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.著, ) https://savannah.gnu.org/bugs/?50357