compact_enc_det

文字コードの判別

[23] 文字列であるはずのバイト列からその文字コード (文字符号化) を決定するには、 決め打ち (例: UTF-8 固定)、 メタ情報 (例: charset 引数) 利用、 バイト列自体からの推定など、 いろいろな手法があります。

[24] 推定手法やそれらの組合せは不確実性を伴うものの、現実には非常に広範囲かつ頻繁に用いられています。

文字コードの決定

[92] 文字コードの決定は、 バイト列とそれに関係する一連の情報から、そのバイト列の解釈に使う文字符号化を決定する操作です。

[93] ファイル形式転送プロトコルプラットフォーム、 各種文字コード体系、その他慣習や互換性等が絡んだ複雑な問題です。

[94] それぞれによっていろいろな規定や実装戦略がありますが、次のように一般化できます。

[95] 文字コードの決定
  1. [96] 決定的指定
  2. [97] BOM
  3. [98] 上書き指定
  4. [99] 転送プロトコルによる指定
  5. [100] ファイル形式依存の指定の検知
  6. [101] 環境符号化の継承
  7. [102] バイト列等からの推定
  8. [103] プラットフォーム設定に基づく既定値
  9. [104] 最終既定値

[114] 通常は符号化を1つ決定することがこの手順群の目的ですが、 文字コード指定メニューの推奨候補の選出のように、 いくつも符号化の候補を抽出するのが良い場面もあります。

ファイル形式の判定

[106] 当該バイト列がどのような性格で、どのようなファイル形式データ形式なのかがわかれば、 文字コードの決定の処理が限定されることがあります。

[107] 当該ファイル形式等に決定方法の規定があれば、それに従うことになります。

[25] そうでなくても内容がある程度限定される場合は、それを前提とした検出手法を採用できます。


[108] 場合によってはファイル形式の検出と文字コードの決定が同時に処理されることがあります。 sniffing

[109] エディターテキストファイルを開く場合など、 特定のファイル形式であるとは判明していないものの、 特定のファイル形式の特徴をも文字コードの判定に活用できる場合があります。


[105] Web の場合については encoding sniffing algorithm を参照。

[56] それ以外のファイル形式依存の方法については charset sniffing も参照。

明示的な指定

[110] 利用者文字符号化を明示的に指定する手段が提供されることがあります。 文字コード指定メニュー

[111] 通常はこれが最優先されるべきですが、セキュリティー等の理由で好ましくないとされる場合もあります。


[112] CLIコマンドラインオプションAPI引数などプログラムの実行者が明示的に指定する手段が提供されることがあります。

[113] こうした方法の指定が最優先されるべきか、他の指定を優先するべきかは、時と場合によります。 XHRoverride charsetBOM よりは優先されないなど、 他の指定が優先されることもあります。


[115] ファイル形式によって確定的な符号化を1つ選べることがあります。

[117] 例えばファイル形式WebVTT と確定しているなら、 文字コードUTF-8 と断定できます。

[116] エディターテキストファイルとして開く場合のように、 ファイル形式に基づく確定的な決定は利用者の指定で上書きできることが望ましい場合があります。

転送プロトコルによる指定

[118] HTTPヘッダーMIMEヘッダーContent-Type: に指定された MIME型文字コードを表す charset 引数を伴っている場合、 これが転送プロトコルによる指定に当たります。

[119] その指定方法や解釈方法にはMIME型ごとに少しずつ違いがあるので注意も必要です。 charset

[120] Web では MIME型による規定の違いは必ずしも尊重されず、ほぼ一律に (MIME charset ではなく) Encoding Standard符号化ラベルに読み替えられて解釈されています。 encoding sniffing algorithm, x-user-defined

[121] MIMEHTTPcharset既定値US-ASCIIISO-8859-1 とする規定を持っていましたが、 実情とまったく一致しておらず完全に無視されてきた歴史を持ちます。 charset charset の不存在を HTTPMIME文字コードの暗黙的指定とみなすべきではありません。

[122] HTTPサーバーISO-8859-1UTF-8 やその他各地域の一般的な文字コードを機械的に charset として指定することがあります。 こうした機械的な指定は実態と乖離していることがしばしばあります。 Webブラウザーによる文字コード判定の失敗事例集

[123] 機械的な指定と著者による意図的な指定を区別するのは困難であり、 原則的には盲信することとなりますから、 文字コード指定メニューなどそれを手動で上書きできる機能が必須となります。

指定の読み替え

[206] 文字コードの指定には色々な表現法があります。また、それぞれに複雑な事情が色々あります。 指定された文字コードの名前等はそのまま使うのではなく、適宜の読み替えが必要になります。

[207] HTMLprescan では、 ASCII 系の文字コードであるにも関わらず UTF-16 系の文字コードが指定されたとき、これを UTF-8 に読み替えることになっています。 prescan, UTF-16, 符号化ラベル

[208] x-user-defined は歴史的理由により Windows-1252 に読み替えられることがあります。 x-user-defined, prescan

[209] Web では同じ符号化にいろいろな符号化ラベルがあります。 本来は異なる文字コードを指していた符号化ラベルが、 歴史的理由によって統合されている場合が多々あります。

[210] 同じ文字コード名でもインターネットメールWeb とで異なる歴史的経過を辿っており、異なる読み替えが必要となる場合もあります。

環境からの継承

[124] フレームとしての埋め込みHTML から CSSJavaScript の参照のように、「外側」からの指定が「内側」で使えることがあります。 環境符号化

BOM

[1] Web では歴史的事情により BOM の存在がかなり重視されています。 encoding sniffing algorithm

[57] BOM に対応した仕様や実装でも、どの文字符号化BOM を検知するかはかなりブレがあります。 現在の WebUTF-16UTF-8 に限定しています。 過去の WebWeb 以外の実装はそれ以外にもいろいろなものに対応していたり、 いなかったりします。

[132] BOM による検知は常に適用できるものではなく、使わない場合もあります。 例えばファイル全体ではなくプロトコル要素として用いられる文字列片では BOM が認められていない場合が一般的であり、その場合たとえ BOM のように見えたとしてもそれは本来の文字列の先頭です。 文字コードの判定には使えません。

[133] ZIPファイルファイル名文字コードの判定では BOM 検査を行いません。

ファイル形式依存の方法による検知

[173] HTML では <meta charset> が、 XML では <?xml encoding="" が、 CSS では @charset文字コードの指定の構文です。各仕様はこれを検出する方法を定めています。 encoding sniffing algorithm 他のファイル形式のいくつかにも似たような構文があります。 文字コードの指定, テキストファイルの先頭

[174] また、テキストエディター文字コードの指定の構文を決めていることがあります。 いくつかのプログラミング言語等もこれを採用しています。 -*- coding -*-, vim:, 局所変数群リスト, テキストファイルの先頭

[175] WebVTTWEBVTT など、ファイル形式が確定できる文字列テキストファイルの先頭に検知できれば、 文字コード自体が明記されていなくても自動的にそのファイル形式の規定する文字コードと推定できることがあります。

バイト列等からの推定

[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 でよく用いられました。日本など乱立が著しかった地域に多く見られます。

[136] TOPICS - VC, , https://web.archive.org/web/19980131160510fw_/http://www.villagecenter.co.jp/cgi-bin/contents.cgi?0=TOPICS
<body bgcolor="black" text="white" link="yellow" vlink="#FF8080">
<!--
あいうえおかきくけこさしすせそたちつてと
IEが EUC を認識しないので、その対策です。(^_^;
-->

判定器が必要な場面

[26] 文字コードの判定応用

決定に使う入力バイト列の長さと範囲

資源ヘッダー, sniffing, encoding sniffing algorithm

出所とロケール情報による推測

[138] 判定したいバイト列の出所 (例えば取得に使った URLTLD) や関係するロケール系の情報が文字コードの決定に使われることがあります。

[86] 利用し得る情報の例:

[141] URLファイル名ドメイン名から利用できる情報の例:

[169] 利用方法:

TLD の利用

[204] 頻度解析等の手法バイト列だけでは似た構造の文字コードの判定に失敗することが少なくないので、 他の情報を補助的に使うことが試みられています。 TLD は特に有力な情報源と考えられています。

[205] ccTLD は、一部の国際的に商業化されたものを除けば、 ほぼ当該地域で使われています。従って当該地域の一般的な文字コードが使われている可能性が、 他の地域文字コードよりずっと高いと考えられます。


[196] cedURL の情報があればヒントとして使うことがあります。 >>43

[197] .hu の場合、ハンガリー語では Latin1Latin2 の区別が難しいとされ、それを考慮したモードに切り替わります。 >>43

[198] .com はヒントとして重視されません。 >>43


[200] FirefoxTLD を判定に重視しています。

[39] 現行実装である chardetng では TLD に基づき動作モードが切り替わります。 >>38, >>202, >>201

[203] かつては HTML Standard の既定値に関する規定にも TLD に基づくものを取り込ませようと試みていたようですが、 うまくいっていません。

[211] chardetng は次の各行の最初に示すような動作モードを持っており、 それぞれその続きに示すような TLD と対応付けられています。 >>202

Arabic ae af bh dz eg iq ir jo kw lb ly ma mr om pk ps qa sa sd sy tn xn--lgbbat1ad8j xn--mgb2ddes xn--mgb9awbf xn--mgba3a4f16a xn--mgbaam7a8h xn--mgbah1a3hjkrd xn--mgbai9azgqp6j xn--mgbayh7gpa xn--mgbc0a9azcg xn--mgbcpq6gpa1a xn--mgberp4a5d4ar xn--mgbpl2fh xn--mgbtx2b xn--ogbpf8fl xn--pgbs0dh xn--q7ce6a xn--wgbh1c xn--wgbl6a xn--ygbi2ammx ye
Baltic lt lv
CentralCyrillic ba
CentralIso hu pl si
CentralWindows cz hr ro sk
Cyrillic bg by kg kz md mk mn rs ru su tj tm ua uz xn--80ao21a xn--90a3ac xn--90ae xn--90ais xn--d1alf xn--j1amh xn--l1acc xn--p1ai
Eu eu xn--e1a4c xn--qxa6a
Generic ac ai bz cb cc cd cx dj fm in la me ms nu st tk to tv vc vu (その他)
Greek cy gr xn--qxam
Hebrew il
IcelandicFaroese fo is
Japanese jp
Korean kp kr xn--3e0b707e
Simplified cn xn--fiqs8S xn--fiqz9S
SimplifiedTraditional sg xn--clchc0ea0b2g2a9gcd xn--yfro4i67o
Thai th xn--o3cw4h
Traditional tw xn--kprw13d xn--kpry57d
TraditionalSimplified hk mo xn--j6w193g xn--mix891f
TurkishAzeri az tr
Vietnamese vn
Western edu gov mil xn--54b7fta0cc xn--fzc2c9e2c xn--xkc2al3hye2a (その他の2文字)
WesternArabic my xn--mgbx4cd0ab
WesternCyrillic am ge xn--node xn--y9a3aq

[212] 比較的新しい時代に作られた TLD である IDN の物も含まれていますが、 既存の Webサーバーに割り当てられている場合に対応するためだと説明されています。 >>199, >>202

[213] 最近の新しい gTLD は Generic になります。

[214] 新しい ccTLD は Generic にならず、なぜか Western に収容されます。 欧米等の ccTLD も既定値 Western として定義から省略されています。

[215] 現行および過去の ccTLD との関係を整理すると次のようになります。

  • [216] 明示的に分類されているもの: ac ae af ai am az ba bg bh by bz cc cd cn cx cy cz dj dz eg eu fm fo ge gr hk hr hu il in iq ir is jo jp kg kp kr kw kz la lb lt lv ly ma md me mk mn mo mr ms my nu om pk pl ps qa ro rs ru sa sd sg si sk st su sy th tj tk tm tn to tr tv tw ua uz vc vn vu ye
  • [217] 明示されず Western に分類されるもの
    • [218] 西欧北米およびそれらのその他の海外領土: ad at be ca ch de es fr gb gg gi ie it je li lu mc nl pm pt sh sm tf uk us va
    • [219] 北欧およびそれらのその他の海外領土: ax bv dk ee fi gl no se sj
    • [220] 南欧: al ht mt
    • [221] オセアニア: as au ck fj gu hm ki mh mp nc nf nr nz pf pg pn pw sb wf ws
    • [222] 中南米: ag an ar aw bb bj bm bo bq br bs cl co cr cu cv cw dm do ec fk gf gp gs gt gy hn jm kn ky lc mx ni pa pe pr py sr tc tt uy ve vg vi
    • [223] アフリカ: ao bf bi bw cf cg ci cm eh er et ga gd gh gm gn gq gw ke km lr ls mg ml mq mu mv mw mz na ne ng re rw sc sl sn so ss sv sx sz td tg tz ug yt za zm zw
    • [224] 東南アジア南アジア: bd bn bt id im io kh lk mm np ph tl tp
    • [225] その他: aq
    • [226] 現在および過去に ccTLD として使われていないものすべて

[227] 現地の公用語宗主国との関係、 フォント依存符号化の分布などを考慮すると、 これらを Western に分類するのはおおむね妥当な選択と思われます。

[228] ccTLD が近年新設された事例をみると Western に分類して問題なさそうですが、 基本的には独立前のと同じ値を引き継ぐのが妥当でしょう。 この実装戦略を模倣するなら、未知のものは Generic に分類するのが妥当と思われます。

ロケールの利用

[87] ロケールが判定のヒントに使われることがあります。 ZIPファイルの文字コード

[195] ced利用者インターフェイス自然言語の情報があればヒントとして使うことがあります。 >>43


[178] HTMLテキストファイルnavigate では、 他の方法で決められないときの既定値ロケール依存となっています。 >>177

[179] より正確に言えば、実装定義または利用者指定の既定の文字符号化とすると定められています。 >>177

[180] 制御された環境や文書の符号化を予め決められる環境では、 UTF-8既定値とするのがよい (suggested) とされます。 例えば新しいネットワークの専用の利用者エージェントではそうできると述べられています。 >>177

[181] 具体的にそのような事例があるのかは不明です。 仕様書としては可能性を狭めないために「新しいネットワーク」 のようなものを想定しているのでしょうが、 現実的にそうしたものが大々的に導入される機会があるかは不透明です。 (例えば HTTPSHTTP/2 への移行でも、サーバー内容は従来のままなので、 切り替えの機会とはできなかったわけで。) 特定のイントラネットや新しい種類の端末の専用ネットワークでも、 わざわざ既定値を変えるための設定や実装の変更よりは HTTP charset の指定を徹底させる方向性の方が楽そうで。

[182] それ以外の環境に対しては、 利用者ロケール利用者がよく見るWebページ自然言語符号化と相関があると考えられるため、 ロケール典型的には依存 (typically dependent) して既定値が定まるとされます。 >>177 ロケール依存の既定の文字コード

[194] UTF-8頻度解析等の手法で高い確率で判定可能です。 であるなら UTF-8 を既定値にするよりも、 既定値は Web 初期の文字コードの指定の慣習が無かった時代の Webサイトをより良く救済できる可能性が高い値を選ぶのが良いと考えられます。

符号構造や出現頻度などによる総合的な推測

[2] 任意のテキストデータ文字コードの判定には、 文字コードバイト範囲や、 出現文字の頻度・確率の情報が使われています。

[58] 平成時代中頃までの古典的な方法では、 文字符号化によって符号の構造が異なることを利用し、 ある文字コード体系で出現する符号かそうでないかという構造的知識を主に使っていました。 しかしこの方法単独では符号構造が重複する領域で互いの区別が付きづらく、 あまり精度が上げられませんでした。 ただ、実装が容易ではあるので、幅広く用いられましたし、現在でも使われることは珍しくありません。

[59] 例えばシフトJIS日本語EUCは第1バイトに使われるバイト、 第2バイトに使われるバイトの範囲がそれぞれ違っていますので、 その範囲に収まるかによってどちらか判断できることが多いです。 しかし完全に重なる部分もあるため、そのような符号ばかりだと正しく判定できません。

[60] また、半角カタカナを利用すると両者の重なる領域が著しく増えるため、 誤判定が多くなり、頻繁に半角カタカナ文字化けを目にすることになります。 これは半角カタカナが嫌われる大きな要因の1つにもなっていました。

[5] 特に日本キリル文字圏では、複数の文字コードが同程度に広く使われていたために自動判定が重宝されていました。

実装

出現頻度等による実装

[176] 出現頻度等による実装:


[3] universalchardet は、 MozillaWebページの表示のために開発したものです。 多くのプラットフォームに移植されて使われています。

[4] 次の符号化に対応しています:

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

[6] データだけで未実装: iso-8859-2 windows-1250

[82] CharamelPythonライブラリーです。機械学習によって Python が標準で対応するすべての符号化に対応したと謳っています。 >>36

[83] 実際に判定させてみると、他の判定器と比べて精度は今ひとつのようにも思われます。 その中には類縁の他の符号化と判断されたものがあり、 使用している文字次第でどちらとも判定できるので誤判定ではないと言えるものもありますが、 それらを除外しても不一致が多いように感じられます。 機械学習の方法による不透明なバイナリーデータを判定に用いているため、 改善も困難と思われます。

[85] 付属の試験データ >>31 は実際の Webページらしきものやその他のテキストデータが含まれますが、 各文字コードには機械的に変換したものと見られます。 中には非ASCII文字が1つも含まれないデータしかない符号化もあり、 試験データとして精査されたものとは思えません。

符号構造のみによる実装

[54] 符号構造のみによる実装:

[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

テストデータ

関連

[55] 文字コード選択メニュー

メモ

[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ビット符号の区別が不可能です。

[79] 符号構造が限定される場合なら、その限定される特徴で判定したほうが高速かつ確実なことが多いので、 この手法が役に立つことはほぼないといっていいでしょう。

[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 → 言語設定から決めた後補を順に試してエラーにならなければ採用 → 判定器。 最初から判定器を使えばいいようにも思われるが、判定器の精度が不十分なので言語依存の決定が増やされてきた経緯のようで。