[23]
文字列であるはずのバイト列からその文字コード (文字符号化)
を決定するには、
決め打ち (例: UTF-8 固定)、
メタ情報 (例: charset 引数) 利用、
バイト列自体からの推定など、
いろいろな手法があります。
[24] 推定手法やそれらの組合せは不確実性を伴うものの、現実には非常に広範囲かつ頻繁に用いられています。
[92] 文字コードの決定は、 バイト列とそれに関係する一連の情報から、そのバイト列の解釈に使う文字符号化を決定する操作です。
[93] ファイル形式、転送プロトコル、プラットフォーム、 各種文字コード体系、その他慣習や互換性等が絡んだ複雑な問題です。
[94] それぞれによっていろいろな規定や実装戦略がありますが、次のように一般化できます。
[114] 通常は符号化を1つ決定することがこの手順群の目的ですが、 文字コード指定メニューの推奨候補の選出のように、 いくつも符号化の候補を抽出するのが良い場面もあります。
[106] 当該バイト列がどのような性格で、どのようなファイル形式やデータ形式なのかがわかれば、 文字コードの決定の処理が限定されることがあります。
[107] 当該ファイル形式等に決定方法の規定があれば、それに従うことになります。
[25] そうでなくても内容がある程度限定される場合は、それを前提とした検出手法を採用できます。
[108]
場合によってはファイル形式の検出と文字コードの決定が同時に処理されることがあります。
[109] エディターでテキストファイルを開く場合など、 特定のファイル形式であるとは判明していないものの、 特定のファイル形式の特徴をも文字コードの判定に活用できる場合があります。
[105] Web の場合については encoding sniffing algorithm を参照。
[56] それ以外のファイル形式依存の方法については charset sniffing も参照。
[110]
利用者が文字符号化を明示的に指定する手段が提供されることがあります。
[111] 通常はこれが最優先されるべきですが、セキュリティー等の理由で好ましくないとされる場合もあります。
[112] CLI のコマンドラインオプションや API の引数などプログラムの実行者が明示的に指定する手段が提供されることがあります。
[113]
こうした方法の指定が最優先されるべきか、他の指定を優先するべきかは、時と場合によります。
XHR の override charset が BOM よりは優先されないなど、
他の指定が優先されることもあります。
[115] ファイル形式によって確定的な符号化を1つ選べることがあります。
[118]
HTTPヘッダー
や
MIMEヘッダーの
Content-Type:
に指定された
MIME型が文字コードを表す
charset
引数を伴っている場合、
これが転送プロトコルによる指定に当たります。
[119]
その指定方法や解釈方法にはMIME型ごとに少しずつ違いがあるので注意も必要です。
[120]
Web では MIME型による規定の違いは必ずしも尊重されず、ほぼ一律に
(MIME charset ではなく) Encoding Standard の符号化ラベルに読み替えられて解釈されています。
[121]
MIME や HTTP は charset の既定値を US-ASCII や
ISO-8859-1 とする規定を持っていましたが、
実情とまったく一致しておらず完全に無視されてきた歴史を持ちます。
charset の不存在を HTTP や MIME の文字コードの暗黙的指定とみなすべきではありません。
[122]
HTTPサーバーは ISO-8859-1 や UTF-8 やその他各地域の一般的な文字コードを機械的に
charset として指定することがあります。
こうした機械的な指定は実態と乖離していることがしばしばあります。
[123] 機械的な指定と著者による意図的な指定を区別するのは困難であり、 原則的には盲信することとなりますから、 文字コード指定メニューなどそれを手動で上書きできる機能が必須となります。
[124]
フレームとしての埋め込みや HTML から CSS や JavaScript
の参照のように、「外側」からの指定が「内側」で使えることがあります。
BOM[1]
Web では歴史的事情により BOM の存在がかなり重視されています。
[57]
BOM に対応した仕様や実装でも、どの文字符号化の BOM を検知するかはかなりブレがあります。
現在の Web は UTF-16 と UTF-8 に限定しています。
過去の Web や Web 以外の実装はそれ以外にもいろいろなものに対応していたり、
いなかったりします。
[132]
BOM
による検知は常に適用できるものではなく、使わない場合もあります。
例えばファイル全体ではなくプロトコル要素として用いられる文字列片では
BOM が認められていない場合が一般的であり、その場合たとえ BOM
のように見えたとしてもそれは本来の文字列の先頭です。
文字コードの判定には使えません。
[173]
HTML では <meta charset> が、
XML では <?xml encoding="" が、
CSS では @charset
が文字コードの指定の構文です。各仕様はこれを検出する方法を定めています。
[174]
また、テキストエディターが文字コードの指定の構文を決めていることがあります。
いくつかのプログラミング言語等もこれを採用しています。
-*- coding -*-, vim:, 局所変数群リスト, テキストファイルの先頭
[175]
WebVTT の WEBVTT など、ファイル形式が確定できる文字列がテキストファイルの先頭に検知できれば、
文字コード自体が明記されていなくても自動的にそのファイル形式の規定する文字コードと推定できることがあります。
[125] バイト列に含まれるバイトを想定される文字コードの符号構造と比較したり、 自然言語の文字の出現頻度の統計データと比較したりして、 使われている文字コードを推定する手法群があります。
[126] 仕組み上、文字コードを断定することは不可能ですが、 実用上かなり多くの場合に正確な判断を下すことが出来ます。
[127] ローカルファイルや古い Webサイトなど、これ以外に信頼できる方法がないことも多いです。
[128]
HTML では頻度解析等の手法と呼ばれ、大まかな枠組みのみとはいえ規定があります。
[129]
UTF-8 はかなり確実に判定できることが知られています。
[130]
ASCII文字のみで構成される場合、復号のみを考慮するなら ASCII
でも ISO-8859-1 でも Windows-1252 でも UTF-8 でも EUC-JP
でもどの回答でも正解になりますが、
その後の処理を考慮すると判定不能と判断することが望ましい場合があります。
[134]
フォント依存符号化を使った HTML文書では、
<font face>
を判定の補助情報に使う必要があります。
[131] バイナリーデータを与えた場合にバイナリーと判定する判定器もあります。 この挙動が望ましいかどうかは時と場合によります。 既にバイナリーデータを除外したテキストファイルのみが入力のときは、 無理にでもどれかの文字符号化と推定するか、判定不能と返す方がいいことも多いです。
[135] 文字コードの判定を助けるため、紛らわしい他の文字コードに出現しない文字を含めたり、 当該文字コードで典型的な文字を最初の方に含めたりする技法が使われることがあります。
[137] 文字コードが乱立しながら頻度解析等の手法が未発達だった平成時代初期の Web でよく用いられました。日本など乱立が著しかった地域に多く見られます。
<body bgcolor="black" text="white" link="yellow" vlink="#FF8080"> <!-- あいうえおかきくけこさしすせそたちつてと IEが EUC を認識しないので、その対策です。(^_^; -->
[138] 判定したいバイト列の出所 (例えば取得に使った URL の TLD) や関係するロケール系の情報が文字コードの決定に使われることがあります。
[86] 利用し得る情報の例:
From: のメールアドレスNewsgroups: のニュースグループContent-Location:Content-Language:Content-Disposition: の filename[141] URL やファイル名やドメイン名から利用できる情報の例:
[169] 利用方法:
[204] 頻度解析等の手法はバイト列だけでは似た構造の文字コードの判定に失敗することが少なくないので、 他の情報を補助的に使うことが試みられています。 TLD は特に有力な情報源と考えられています。
[205] ccTLD は、一部の国際的に商業化されたものを除けば、 ほぼ当該地域で使われています。従って当該地域の一般的な文字コードが使われている可能性が、 他の地域の文字コードよりずっと高いと考えられます。
[196] ced は URL の情報があればヒントとして使うことがあります。 >>43
[197]
.hu の場合、ハンガリー語では Latin1 と Latin2
の区別が難しいとされ、それを考慮したモードに切り替わります。 >>43
[198]
.com はヒントとして重視されません。 >>43
[200] Firefox は TLD を判定に重視しています。
[39] 現行実装である chardetng では TLD に基づき動作モードが切り替わります。 >>38, >>202, >>201
[203] かつては HTML Standard の既定値に関する規定にも TLD に基づくものを取り込ませようと試みていたようですが、 うまくいっていません。
[87] ロケールが判定のヒントに使われることがあります。
[195] ced は利用者インターフェイスの自然言語の情報があればヒントとして使うことがあります。 >>43
[178] HTML やテキストファイルの navigate では、 他の方法で決められないときの既定値がロケール依存となっています。 >>177
[179] より正確に言えば、実装定義または利用者指定の既定の文字符号化とすると定められています。 >>177
[180] 制御された環境や文書の符号化を予め決められる環境では、 UTF-8 を既定値とするのがよいとされます。 例えば新しいネットワークの専用の利用者エージェントではそうできると述べられています。 >>177
charset の指定を徹底させる方向性の方が楽そうで。[182]
それ以外の環境に対しては、
利用者のロケールが利用者がよく見るWebページの自然言語や符号化と相関があると考えられるため、
ロケールに典型的には依存して既定値が定まるとされます。
>>177
[2] 任意のテキストデータの文字コードの判定には、 文字コードのバイトの範囲や、 出現文字の頻度・確率の情報が使われています。
[58] 平成時代中頃までの古典的な方法では、 文字符号化によって符号の構造が異なることを利用し、 ある文字コード体系で出現する符号かそうでないかという構造的知識を主に使っていました。 しかしこの方法単独では符号構造が重複する領域で互いの区別が付きづらく、 あまり精度が上げられませんでした。 ただ、実装が容易ではあるので、幅広く用いられましたし、現在でも使われることは珍しくありません。
[59] 例えばシフトJISと日本語EUCは第1バイトに使われるバイト、 第2バイトに使われるバイトの範囲がそれぞれ違っていますので、 その範囲に収まるかによってどちらか判断できることが多いです。 しかし完全に重なる部分もあるため、そのような符号ばかりだと正しく判定できません。
[60] また、半角カタカナを利用すると両者の重なる領域が著しく増えるため、 誤判定が多くなり、頻繁に半角カタカナの文字化けを目にすることになります。 これは半角カタカナが嫌われる大きな要因の1つにもなっていました。
[5] 特に日本とキリル文字圏では、複数の文字コードが同程度に広く使われていたために自動判定が重宝されていました。
[176] 出現頻度等による実装:
[3] universalchardet は、 Mozilla が Webページの表示のために開発したものです。 多くのプラットフォームに移植されて使われています。
utf-8 utf-16be utf-16le iso-2022-cn big5 x-euc-tw gb18030 hz-gb-2312
iso-2022-jp shift_jis euc-jp iso-2022-kr euc-kr
iso-8859-5
koi8-r
windows-1251
x-mac-cyrillic ibm866 ibm855 iso-8859-7
tis-620
windows-1253
iso-8859-8 windows-1255 windows-1252
[82] Charamel は Python 用ライブラリーです。機械学習によって Python が標準で対応するすべての符号化に対応したと謳っています。 >>36
[83] 実際に判定させてみると、他の判定器と比べて精度は今ひとつのようにも思われます。 その中には類縁の他の符号化と判断されたものがあり、 使用している文字次第でどちらとも判定できるので誤判定ではないと言えるものもありますが、 それらを除外しても不一致が多いように感じられます。 機械学習の方法による不透明なバイナリーデータを判定に用いているため、 改善も困難と思われます。
[85] 付属の試験データ >>31 は実際の Webページらしきものやその他のテキストデータが含まれますが、 各文字コードには機械的に変換したものと見られます。 中には非ASCII文字が1つも含まれないデータしかない符号化もあり、 試験データとして精査されたものとは思えません。
[76] LV Homepage (in Japanese), , https://web.archive.org/web/20010119052900/http://www.mt.cs.keio.ac.jp/person/narita/lv/index_ja.html
現在の自動選択の方法は簡単なものです. ファイルを先頭から読み込んでいって, 8ビット目が立っている文字があった場合, 『その行』の中で euc-japan で使用される領域のみを使っていれば euc-japan, そうでなければ shift-jis です. つまり,『漢字らしきものを含む最初の一行』で判断しています. 8ビット目が立っている文字が見つからなければ いつまでも自動選択のままの状態が続き, 判断が必要になったときに判断します. shift-jis の片仮名のみを使用した場合や, 運の悪いときは, 誤って euc-japan と認識されます.
[70] Add UTF-7 to replacement encoding list? / Encoding sniffing · Issue #68 · whatwg/encoding, https://github.com/whatwg/encoding/issues/68
[71] Encoding: make it clear sniffing for UTF-8 is not acceptable by annevk · Pull Request #14455 · web-platform-tests/wpt · GitHub, https://github.com/web-platform-tests/wpt/pull/14455
[80] How to reliably guess the encoding between MacRoman, CP1252, Latin1, UTF-8, and ASCII - Stack Overflow, https://stackoverflow.com/questions/4198804/how-to-reliably-guess-the-encoding-between-macroman-cp1252-latin1-utf-8-and
[49] [ptexenc] 入力ファイルの文字コードの自動判定 · Issue #142 · texjporg/tex-jp-build, https://github.com/texjporg/tex-jp-build/issues/142
[69] >>68 Accept-Language:, User-Agent: (OS),
アクセス者の IPアドレスを使って文字符号化を推定する。
平成25年。
[78] 対応している符号化を順番に試してエラーにならなかったものを採用するという実装を「文字コードの判定」だと称しているものがたまにあります。 このような方法は符号構造がまったく違う符号の区別になら使えますが、 多くの8ビット符号の区別が不可能です。
[89] Sub-Zero.bundle/Contents/Libraries/Shared/subliminal_patch/subtitle.py at master · pannal/Sub-Zero.bundle · GitHub, https://github.com/pannal/Sub-Zero.bundle/blob/master/Contents/Libraries/Shared/subliminal_patch/subtitle.py
[90] >>89 BOM → 言語設定から決めた後補を順に試してエラーにならなければ採用 → 判定器。 最初から判定器を使えばいいようにも思われるが、判定器の精度が不十分なので言語依存の決定が増やされてきた経緯のようで。