[23] 
[[文字列]]であるはずの[[バイト列]]からその[[文字コード]] ([[文字符号化]])
を決定するには、
決め打ち (例: [[UTF-8]] 固定)、
[[メタ情報]] (例: [CODE[charset]] [[引数]]) 利用、
[[バイト列]]自体からの推定など、
いろいろな手法があります。

[24] 
推定手法やそれらの組合せは不確実性を伴うものの、現実には非常に広範囲かつ頻繁に用いられています。

* 文字コードの決定

[92] 
[DFN[文字コードの決定]]は、
[[バイト列]]とそれに関係する一連の情報から、その[[バイト列]]の解釈に使う[[文字符号化]]を決定する操作です。

[93] 
[[ファイル形式]]、[[転送プロトコル]]、[[プラットフォーム]]、
各種[[文字コード]]体系、その他慣習や互換性等が絡んだ複雑な問題です。

[94] 
それぞれによっていろいろな規定や実装戦略がありますが、次のように一般化できます。

[FIG(steps)[ [95] [[文字コードの決定]]

= [96] 決定的指定
= [97] [CN[BOM]]
= [98] 上書き指定
= [99] [[転送プロトコル]]による指定
= [100] [[ファイル形式]]依存の指定の検知
= [101] [[環境符号化]]の継承
= [102] [[バイト列]]等からの推定
= [103] [[プラットフォーム]]設定に基づく既定値
= [104] 最終既定値

]FIG]

[114] 
通常は[[符号化]]を1つ決定することがこの[[手順群]]の目的ですが、
[[文字コード指定メニュー]]の推奨候補の選出のように、
いくつも[[符号化]]の候補を抽出するのが良い場面もあります。


** インターフェイス

[391] 
[[文字コードの決定]]の処理の入出力は、どのような場面で使われるかによっても変わってきます。

[392] 
入力となり得るもの:

- [395] 判定したいデータ本体 : >>410
- [402] [[利用者]]による明示的な指定 : >>110
- [403] [[輸送路プロトコル]]による明示的な指定 : >>118
- [404] 継承されるべき環境の[[符号化]] : >>124
- [393] [[ファイル形式]] : >>106 >>173
- [405] データの出所に関する情報 : >>138
- [406] 利用環境に関する情報 : >>138
- [407] 候補となるべき[[符号]]の限定 : >>384

[394] 
出力となり得るもの:

- [396] 結果として得られた[[符号化]] : >>428
-- [397] [[符号化]]の種別1つ
--- [399] 「結果なし」
--- [400] 「バイナリー」 >>346
-- [398] [[符号化]]のリスト : >>114
- [409] 結果として得られた[[フォント依存符号化]]
- [401] 結果として得られた[[ファイル形式]] : >>108
- [408] 結果の確信度 : >>447



;; [427] 
判定器の入出力の設計は、 [[Web]] の場合を例にすると、
[[encoding sniffing algorithm]]
の他、
[[復号器]],
[[符号化の変更]],
[[MIME sniffing]],
[[speculative HTML parser]],
[[HTMLの字句化]],
[[fetch]] ([[ネットワーク]], [[キャッシュ]]その他)
といった処理を、無駄なデータ複製を抑制しつつ、 
適度に[[プロセス]]や[[スレッド]]を分離しながら、
いかに全体として統合していくか、
とういう総合設計の問題の一部分となります。




*** 入力バイトストリーム

[410] 
[[符号化]]が外部的情報だけでなくデータの内容の検査からも決める場合、
当然のことながら判定器にデータを構成する[[バイト列]]を与える必要があります。

[411] 
[[バイト列]]をどのように与えるのが良いかは[[プラットフォーム]]と[[応用]]により様々で、
一概には言えません。

-*-*-

[414] 
[[ファイル名の文字コード]]の処理のような小さなデータしか扱わないと決めている判定器なら、
[[プログラミング言語]]の基本的な[[バイト列]]型で十分かもしれません。

[412] 
[[HTML]] や [[CSV]] のように巨大かもしれないし小さいかもしれない[[ファイル]]は、
[[バイトストリーム]]として引き渡し、判定器が自由に読めるようにするのが良いと考えられます。

;;
[413] 
自由にとはいいつつ、一般的な実装では先頭から順に好きなところまで読んでいく形になります。
といっても判定器を構成する小判定器群がそれぞれ順に走査していくような
[CITE[UnivCharDet]] 型の[[アーキテクチャー]]を採用するなら、
一度しか先頭から走査できないような[[データ型]]は不都合かもしれません。

[415] 
[[HTTP応答]]など[[ネットワーク]]で転送されてきた巨大かもしれない、
もしかすると無限の長さを持つかも知れない[[ストリーム]]を対象とするときは、
それを対処可能なデータの渡し方を採用する必要があります。

[EG[

[416] よくあるのは、バイト塊を渡す[[メソッド]]と、 [[EOF]]
を渡す[[メソッド]]の2つを用意し、新規データが到着するたびに前者を呼び出す手法でしょうか。

]EG]

[417] 
判定器は、分割して[[バイト]]塊を受領するときは、
前の塊を処理した最終状態を次の塊の最初で復元できるように設計する必要があります。

[EG[
[418] 
例えば2バイト文字の最初の[[バイト]]が塊の最後にあったときは、
そのまま未確定の状態を保持しておき、
次の塊の最初を第2バイトとして処理を再開することになります。
]EG]

[419] 
巨大ファイルの先頭部分だけを判定に使う場合のように不完全な入力を判定器に渡すことを認める場合には、
データの末尾 ([[EOF]]) と末尾ではない最後を区別する手段が必要です。

[EG[
[420] 
例えば2バイト文字の最初の[[バイト]]と解釈出来るものが塊の最後にあったとき、
その続きが [[EOF]] なら不正 (2バイト符号ではない、または壊れたデータ)
と判断できますが、 [[EOF]] ではなく判定のための入力データの末尾なら、
不正かそうでないかは判断できません。


]EG]

[421] 
[[アーキテクチャー]]によっては、判定器から[[応用]]に対してそれ以上追加の入力データの供給が不要であることを通知する手段があってもいいかもしれません。

[EG[
[422] 
例えばバイトの塊を供給されながら動作する判定器は、
入力に [CN[BOM]] があって [[UTF-8]] と確定したら、
それ以上の入力は不要であると通知すると無駄な入力を抑制できます。

]EG]

[426] 
[[HTML]] の [[encoding sniffing algorithm]] の如く、
判定に使う入力の長さや待機時間長に制限がある場合もあります。
[SEE[ [[資源ヘッダー]] ]]
こうした入力の制限は、
判定器の側と判定器に[[バイト列]]を供給する側のどちらで実装するか、
[[ネットワーク]]の実装等を含めた全体構成の実装戦略 (>>427)
次第となることでしょう。

-*-*-

[455] 
[[書庫ファイル]]の[[ファイル名]]のように、
1つだけの入力[[バイト列]]で十分信頼できる結果を導出できるか不安があるときに、
複数の[[ファイル名]]をまとめることで幾分精度を向上できる (かもしれない) 場合があります。

[456] 
[[ZIPファイル]]のように [[UTF-8]] の[[ファイル名]]と[[文字コード]]未詳の[[ファイル名]]を混在させられる[[書庫形式]]もあります。
共通の[[ディレクトリー名]]部分のように、 [[UTF-8]] の[[ファイル名]]を
「正解データ」
として参考にできることがあります。


*** 結果として得られる符号化

[428] 
判定器の出力は[[文字符号化]]の種別です。

[429] 
理想的には正解が1つ即座に返されてほしいですが、必ずしもそれが可能とは限りません。

-*-*-

[430] 
判定器の諸実装は、どれとも決めかねるときは、

- [432] 結果無しを返す
- [431] 
[[ASCII]] や [[windows-1252]] などの既定値を返す

... のどちらかのことが多いようです。他に

- [436] 異常動作する

... ものもあるようです。

;; [437] 判定器の選定時に注意したいポイントです。

[433] 正常動作の2タイプのどちらがいいかは使い方によるので一概には言えませんが、
判定器単体の実装としては結果無しを[[応用]]に伝える方が便利かもしれません。
判定の処理の全体としては、[[テキストファイル]]として処理するのであれば、
何らかの回答を決める必要があります。

[434] [[HTML]] の [[encoding sniffing algorithm]] は、
どうしても決められないときは[[利用者]]の[[ロケール]]から最終回答を決めます。

[435] [[テキストファイル]]としての処理を断念して[[バイナリーファイル]]の処理に移る[[応用]]もあるでしょうから、
その場合は結果無しを最終回答するのでも良いでしょう。

-*-*-

[438] 
候補が複数あるときでも、多くの判定器の実装は最善と思われる1つを返すようです。

[441] 
複数の候補を返す、または返せる判定器の実装もあるようです。

[439] 
[[HTML]] の表示や[[テキストエディター]]の読み込みなど、
大概の処理はどれか1つの結果を選んでその先の処理に進むことになるので、
1つに絞り切る決定的な証拠がなくても、どれかを選ぶしかありません。

[440] 
[[文字コード指定メニュー]]の優先候補表示など、
判定結果を複数提示可能な場面もありますから、
複数の候補を返せるなら、それも悪くないかも知れません。


**** 判定された文字コードの識別

[442] 
[[文字符号化]]の種別は、[[文字コードの識別]]の手法によって伝達することになります。

[443] 
[[文字コードの識別]]は非常に混乱した分野であり、
同じ名前でも違った[[文字符号化]]と解釈されたり、
そもそもその名前が実装されていなかったりといった非互換性に溢れています。
[SEE[ [[文字コードの識別]] ]]

[444] 
[[文字コードの識別]]を確実に行うことは[[相互運用性]]と[[セキュリティー]]のためにどの文脈でも重要には違いないのですが、
[[文字コードの判定]]の処理では特別に重要です。
判定器が返した結果はほとんどの場合に[[復号器]]の入力になりますから、
判定器と[[復号器]]が[[文字コードの識別]]の共通理解を有している必要があります。

[446] 
判定器の諸実装は、 [[IANA charset]] を採用するもの、
[[プログラミング言語]]の標準ライブラリーの名前を採用するもの、
[[iconv]] の名前を採用するものなど方針がバラバラです。
開発過程で二転三転して混乱している実装もあるようです。

[445] 
どの名前がどの[[文字コード]]体系を表すのか標準化され安定しているのは
[CITE[Encoding Standard]]
の[[符号化名]]と[[符号化ラベル]]がほぼ唯一であり、これを中核とすることが望ましいと思われます。
ただし [CITE[Encoding Standard]]
は欧米の [[Web]] 系の[[符号化]]に偏向しており、
[[Web]] 以外や[[アジア]]系の[[符号化]]に弱いのがネックです。

**** 未対応の符号

[457] 
[[文字コードの判定]]の処理が、[[復号器]]が対応できない[[文字符号化]]を回答とすることがあります。
大別して2種類あります。

- [458] [[文字コードの指定]]が未対応の[[文字符号化]]であると主張しているとき
- [459] 判定器が対応しているが[[復号器]]が対応していない[[文字符号化]]を検知したとき

[460] 
>>458 は、例えば [[HTTP]] の [CODE[charset=""]] 
[[引数]]に未知の[[文字符号化]]が指定されたときです。

[461] 
こうした場合、未知の[[符号]]であるとして処理の全体を中断するのが良いと考えられる場合もあれば、
他の[[符号]]としての解釈を試みる場合もあります。

[462] 
[[HTML]] の [[encoding sniffing algorithm]] は、
諸手法のうち前段の手法で未知の[[符号化]]が得られたときは、
採用せず後段の手法を試みるよう定めています。

[463] 
>>460 のように[[符号化ラベル]]が未対応なだけで[[符号]]自体には対応しているときは、
他の手法で救済できる可能性があります。

[464] 
また、共通部分が多い似た[[符号]]が他にあれば、
それを使えば不完全でも[[復号]]できる可能性があります。


[466] 
[[応用]]側から予め対応可能な[[符号]]の一覧を判定器に渡して、
それ以外は出力させないという設計もあり得ます。

[465] 
[[相互運用性]]や[[セキュリティー]]にも関係する問題なので、
関係する仕様との整合性やシステム全体の実装戦略を勘案しつつ決めるべき事項です。

[467] 
どう設計するにせよ、判定器は未知の[[符号化ラベル]]に遭遇しても異常動作をするべきではありませんし、
[[応用]]は判定器が未知の結果を返しても異常動作をするべきではありません。

[248] なお >>384 も参照。

**** 符号の包含と重なり

[SEE[ [[最適な文字コードの選定]] ]]


*** 結果の確信度


[447] 
[[HTML]] の [[encoding sniffing algorithm]] は結果が確定か暫定かの別を持ちます。
[[HTML]] では確定的な[[符号化]]の情報が見つからないときの暫定結果を後からより確定的な情報が得られたときに[[変更][符号化の変更]]できます。

[448] 
[[HTML]] 以外でも、[[文字コードの決定]]の根拠が [[HTTPヘッダー]]等の信頼できる情報なのか、
推定なのかの違いが[[セキュリティー]]その他に関係する場合もあることでしょう。

-*-*-

[449] 
判定器は出力した結果やその他の候補の[[符号化]]それぞれの得点を内部的に持っていることがあります。
[CITE[UnivCharDet]] の系譜の諸実装は[RUBYB[確度][confidence]] [ [N[0]], [N[1]] ]
を計算し、最大のものを結果としています。他の実装にも似たような尺度があります。

[450] 
判定器の実装の中にはこうした値を出力できるものもあります。

[451] 
ただ、こうした値は特定の実装でのみ意味を持つものです。
同じ実装でも版によって判定結果が変わることがあります。
こうした値を得ても、当該判定器の開発者以外にとっては大した情報にはなりません。

[452] 
とはいえ複数の[[符号化]]の候補があるときは、相対的な大小で候補の順位を決めることができます。

[453] 
また、非常に強い可能性なのか、同じくらいの可能性のいくつかの候補なのか、
消去法なのか、といった違いを[[利用者インターフェイス]]でうまく表現できる[[応用]]もあるかもしれません。

[454] 
そのためには、
ただの内部的な値の出力ではなく、
可能な値の範囲とその意味を厳密に定めた判定器と[[応用]]との間の [[API]]
としての値空間が必要です。
現時点でそのような事例は見当たりません。


*** 結果を引き渡すタイミング

[468] 
短い入力しか扱わない判定器なら、[[関数]]のような形で単純に入力に対して出力を返す形で結果を[[応用]]に引き渡す仕組みでも十分です。


[469] 
ネットワークからのデータなど入力サイズが短かったり長かったりし、
時には無限のこともあるなら、いつどのように結果を引き渡すかを考える必要があります。

[470] 
例えば [[HTML]] の場合は入力の最初の1024バイトに [CODE[<meta charset>]]
があればその結果を返せますが、それがなければ最後まで読む必要があるかもしれません。
極端な場合、長く [[ASCII文字]]が続いた後に少しだけ[[非ASCII文字]]が出現することもあり得ます。
[[HTML]] には[[符号化の変更]]の仕組みがあるので、
最後まで読み終わらなくても[[復号]]や[[レンダリングの開始]]を実行して、
後から[[再読み込み]]するという手法を採れます。

[471] 
そうした分野で使う判定器なら、判定器が良いと判断したタイミングまたは[[応用]]が欲したタイミングで暫定結果を[[応用]]側に引き渡し、
引き続き処理を続け、
末端まで到達したら最終結果を[[応用]]側に引き渡す、
といった何度も結果を作って渡せる仕組みが必要になります。


*** 上位層文字符号化の推定

[SEE[ [[文字として符号化された文字やバイト]] ]]

** ファイル形式の判定

[106] 
当該[[バイト列]]がどのような性格で、どのような[[ファイル形式]]や[[データ形式]]なのかがわかれば、
[[文字コード]]の決定の処理が限定されることがあります。

[107] 
当該[[ファイル形式]]等に決定方法の規定があれば、それに従うことになります。

[25] 
そうでなくても内容がある程度限定される場合は、それを前提とした検出手法を採用できます。

[EG[

[472] 
[[WebVTT]] なら [[UTF-8]] と確定できます。

]EG]

[EG[

[473] 
[[ZIPファイル]]の[[ファイル名]]なら、歴史的に [[ZIPファイル]]で利用された事例がある[[文字コード]]体系のいずれかに絞り込めます。

]EG]

[EG[

[474] 
[[HTML]] なら、 [CITE[HTML Standard]] で [[encoding sniffing algorithm]]
として決定手順が定められています。

]EG]

-*-*-

[108] 
場合によっては[[ファイル形式]]の検出と[[文字コード]]の決定が同時に処理されることがあります。
[SEE[ [[sniffing]] ]]

[390] 
[[バイナリー]]判定関連: >>346

[109] 
[[エディター]]で[[テキストファイル]]を開く場合など、
特定の[[ファイル形式]]であるとは判明していないものの、
特定の[[ファイル形式]]の特徴をも[[文字コード]]の判定に活用できる場合があります。

-*-*-

[105] [[Web]] の場合については [[encoding sniffing algorithm]] を参照。

[56] それ以外の[[ファイル形式]]依存の方法については [[charset sniffing]] も参照。

** 利用者や応用からの明示的な指定

[110] 
[[利用者]]が[[文字符号化]]を明示的に指定する手段が提供されることがあります。
[SEE[ [[文字コード指定メニュー]] ]]

[111] 
通常はこれが最優先されるべきですが、[[セキュリティー]]等の理由で好ましくないとされる場合もあります。

-*-*-

[112] 
[[CLI]] の[[コマンドラインオプション]]や [[API]] の[[引数]]など[[プログラム]]の実行者が明示的に指定する手段が提供されることがあります。

[113] 
こうした方法の指定が最優先されるべきか、他の指定を優先するべきかは、時と場合によります。
[CITE[XHR]] の [[override charset]] が [CN[BOM]] よりは優先されないなど、
他の指定が優先されることもあります。

;; [116] 
[[ファイル形式]]によって確定的な[[符号化]]を1つ選べることがあります。
例えば[[ファイル形式]]が [[WebVTT]] と確定しているなら、
[[文字コード]]は [[UTF-8]] と断定できます。
そのような場合ですらも、
[[エディター]]で[[テキストファイル]]として開く場合のように、
[[ファイル形式]]に基づく確定的な決定は[[利用者]]の指定で上書きできることが望ましい場合があります。


** 転送プロトコルによる指定

[118] 
[[HTTPヘッダー]]
や
[[MIMEヘッダー]]の 
[CODE[Content-Type:]] 
に指定された
[[MIME型]]が[[文字コード]]を表す
[CODE[charset]]
[[引数]]を伴っている場合、
これが[[転送プロトコル]]による指定に当たります。

[119] 
その指定方法や解釈方法には[[MIME型]]ごとに少しずつ違いがあるので注意も必要です。
[SEE[ [[charset]] ]]

[120] 
[[Web]] では [[MIME型]]による規定の違いは必ずしも尊重されず、ほぼ一律に
([[MIME charset]] ではなく) [CITE[Encoding Standard]] の[[符号化ラベル]]に読み替えられて解釈されています。
[SEE[ [[encoding sniffing algorithm]], [[x-user-defined]] ]]

[121] 
[[MIME]] や [[HTTP]] は [CODE[charset]] の[[既定値]]を [CODE[US-ASCII]] や 
[CODE[ISO-8859-1]] とする規定を持っていましたが、
実情とまったく一致しておらず完全に無視されてきた歴史を持ちます。
[SEE[ [[charset]] ]]
[CODE[charset]] の不存在を [[HTTP]] や [[MIME]] の[[文字コード]]の暗黙的指定とみなすべきではありません。

[122] 
[[HTTPサーバー]]は [CODE[ISO-8859-1]] や [CODE[UTF-8]] やその他各地域の一般的な[[文字コード]]を機械的に
[CODE[charset]] として指定することがあります。
こうした機械的な指定は実態と乖離していることがしばしばあります。
[SEE[ [[Webブラウザーによる文字コード判定の失敗事例集]] ]]

[123] 
機械的な指定と[[著者]]による意図的な指定を区別するのは困難であり、
原則的には盲信することとなりますから、
[[文字コード指定メニュー]]などそれを手動で上書きできる機能が必須となります。

-*-*-

[197] 
かつては [[Webブラウザー]]の[[フォームの提出]]で
[[query parameter]]
や[[フォームデータ]]に
[CODE[_charset_]]
に[[符号化ラベル]]が設定されて[[サーバー]]側に送出される仕組みがありました。

[232] 
また、これに類似するものとして、一部の [[Webアプリケーション]]は
[CODE[ie]]
のような名前の[[引数]]に[[符号化ラベル]]を設定していました。

[233] 
[[Webアプリケーション]]の[[サーバー]]側の処理 ([[CGIスクリプト]]等)
はこうした入力における指定をあれば、それを採用して[[引数]]の[[復号]]を行っていました。

** データ内部の指定

[559] 
例えば:
[CODE[<meta charset="">]],
[[[CODE[encoding]]宣言]],
[CODE[-*- coding -*-]]
[SEE[ [[charset sniffing]] ]]

*** フォント指定からの推定

[SEE[ [[文字として符号化された文字やバイト]] ]]

** 指定の読み替え

[206] 
[[文字コードの指定]]には色々な表現法があります。また、それぞれに複雑な事情が色々あります。
指定された[[文字コード]]の名前等はそのまま使うのではなく、適宜の読み替えが必要になります。

[207] 
[[HTML]] の [[prescan]] では、 [[ASCII]] 系の[[文字コード]]であるにも関わらず
[[UTF-16]] 系の[[文字コード]]が指定されたとき、これを [[UTF-8]]
に読み替えることになっています。
[SEE[ [[prescan]], [[UTF-16]], [[符号化ラベル]] ]]

[208] 
[[x-user-defined]] は歴史的理由により [[Windows-1252]]
に読み替えられることがあります。
[SEE[ [[x-user-defined]], [[prescan]] ]]

[115] 
[[キリル文字の文字コード]]は、歴史的理由により、[[蒙古語]]を表すことが確実な場合
(例えば [CODE[.mn]] ドメインから取得した場合) に[[ロシア]]系の規格ではなく[[蒙古]]の規格に読み替える必要があります (>>187)。


[209] 
[[Web]] では同じ[[符号化]]にいろいろな[[符号化ラベル]]があります。
本来は異なる[[文字コード]]を指していた[[符号化ラベル]]が、
歴史的理由によって統合されている場合が多々あります。

[210] 
同じ[[文字コード]]名でも[[インターネットメール]]と [[Web]]
とで異なる歴史的経過を辿っており、異なる読み替えが必要となる場合もあります。


** 環境からの継承

[124] 
[[フレーム]]としての[[埋め込み]]や [[HTML]] から [[CSS]] や [[JavaScript]] 
の参照のように、「外側」からの指定が「内側」で使えることがあります。
[SEE[ [[環境符号化]] ]]




** ファイル形式依存の方法による検知

[173] 
[[HTML]] では [CODE[<meta charset>]] が、
[[XML]] では [CODE[[[<?xml]] [SNIP[]] [[encoding=""]]]] が、
[[CSS]] では [CODE[@charset]]
が[[文字コードの指定]]の構文です。各仕様はこれを検出する方法を定めています。
[SEE[ [[encoding sniffing algorithm]] ]]
他の[[ファイル形式]]のいくつかにも似たような構文があります。
[SEE[ [[文字コードの指定]], [[テキストファイルの先頭]] ]]

[174] 
また、[[テキストエディター]]が[[文字コードの指定]]の構文を決めていることがあります。
いくつかの[[プログラミング言語]]等もこれを採用しています。
[SEE[ [CODE[-*- coding -*-]], [CODE[vim:]], [[局所変数群リスト]], [[テキストファイルの先頭]] ]]

[175] 
[[WebVTT]] の [CODE[WEBVTT]] など、[[ファイル形式]]が確定できる[[文字列]]が[[テキストファイルの先頭]]に検知できれば、
[[文字コード]]自体が明記されていなくても自動的にその[[ファイル形式]]の規定する[[文字コード]]と推定できることがあります。


[244] 
[CITE@ja[cmsd_doc_reference.pdf]], [TIME[2015-08-28T09:04:15.000Z]], [TIME[2025-11-23T04:24:09.319Z]] <https://cms.al-design.jp/downloads/EUC-JP/cmsd_doc_reference.pdf#page=69>

>
[LEFT[
[PRE[
<?php require( "cmsdesigner/include/view.php.inc" ); // encoding="euc-jp" ?>
]PRE]
]LEFT]

>
[LEFT[
は、定型文として入れてください。(「// encoding="euc-jp"」は Dreamweaver の文字化け(不具[BR[]]
合?)回避の為のおまじないです。)
]LEFT]

;; [245] [CODE[encoding=""]] の [[sniffing]] を応用した [[hack]] か?




** バイト列等からの推定

[125] 
[[バイト列]]に含まれる[[バイト]]を想定される[[文字コード]]の[[符号構造]]と比較したり、
[[自然言語]]の[[文字]]の出現頻度の統計データと比較したりして、
使われている[[文字コード]]を推定する手法群があります。

[126] 
仕組み上、[[文字コード]]を断定することは不可能ですが、
実用上かなり多くの場合に正確な判断を下すことが出来ます。

[127] 
[[ローカルファイル]]や古い [[Webサイト]]など、これ以外に信頼できる方法がないことも多いです。

[128] 
[[HTML]] では[[頻度解析等の手法]]と呼ばれ、大まかな枠組みのみとはいえ規定があります。
[SEE[ [[頻度解析等の手法]] ]]



[130] 
[[ASCII文字]]のみで構成される場合、[[復号]]のみを考慮するなら [[ASCII]]
でも [[ISO-8859-1]] でも [[Windows-1252]] でも [[UTF-8]] でも [[EUC-JP]]
でもどの回答でも正解になりますが、
その後の処理を考慮すると判定不能と判断することが望ましい場合があります。
[SEE[ [[頻度解析等の手法]] ]]

[134] 
[[フォント依存符号化]]を使った [[HTML文書]]では、
[CODE[<font face>]] 
を判定の補助情報に使う必要があります。
[SEE[ [[頻度解析等の手法]] ]]

[131] 
[[バイナリーデータ]]を与えた場合に[[バイナリー]]と判定する判定器もあります。
この挙動が望ましいかどうかは時と場合によります。
既に[[バイナリーデータ]]を除外した[[テキストファイル]]のみが入力のときは、
無理にでもどれかの[[文字符号化]]と推定するか、判定不能と返す方がいいことも多いです。

*** 判定器を意識した著者による記述

[135] 
[[文字コードの判定]]を助けるため、紛らわしい他の[[文字コード]]に出現しない[[文字]]を含めたり、
当該[[文字コード]]で典型的な[[文字]]を最初の方に含めたりする技法が使われることがあります。

[137] 
[[文字コード]]が乱立しながら[[頻度解析等の手法]]が未発達だった[[平成時代]]初期の
[[Web]] でよく用いられました。[[日本]]など乱立が著しかった地域に多く見られます。

[117] 
[[日本]]では [[Shift_JIS]] と [[EUC-JP]]
の区別のため、
[N[0xFDFE]],
[CODE[美乳]],
[CH[龠]]
などが使われました。
[SEE[ [[文字コード判定器を意識した著者による記述]] ]]

[136] 
[[日本]]の[[平成時代]]前半の [[Webアプリケーション]] ([[CGIスクリプト]]など)
は入力データの[[文字コードの判定]]が必須の処理でした。
正しい[[文字コード]]と確実に認識されるよう、 
[CODE[<input type=hidden>]]
で固定の文字列を用意しておき、
判定の材料とする手法がしばしば使われました。



*** 判定器が必要な場面


[FIG(middle list)[ [26] [[文字コードの判定]]の[[応用]]

- [[encoding sniffing algorithm]]
- [[テキストファイル]]の表示
-- [[テキストエディター]]の「開く」処理
- [[ZIPファイル]]の[[ファイル名]]
- [[RFC 822メッセージ]] ([[MIME]] 以前) 
- [[query parameter]] や[[フォームデータ]]の[[復号]]
- [CODE[mailto:]]
- [[CSV]]
- [[IRC]]
- [[SRT]]
- [[ID3]]
- [[T[SUB[E]]X]]
- [[QRコード]]

]FIG]

-[254] 
[CITE[Googleの検索結果サマリーが半角カタカナだらけ]], [TIME[2020-08-20T23:48:51.000Z]], [TIME[2025-11-23T05:54:04.480Z]] <https://www.shtml.jp/mojibake/google_hankaku.html>
--[255] [CITE[Googleの検索サマリーが「\」やフランス語のアクセント記号だらけ]], [TIME[2020-08-20T23:48:52.000Z]], [TIME[2025-11-23T05:55:00.048Z]] <https://www.shtml.jp/mojibake/google_yen.html>
-- [256] 
[CITE[「痴」「稚」が一杯。英語サイトを作ったら文字化け]], [TIME[2020-08-20T23:48:46.000Z]], [TIME[2025-11-23T05:55:24.455Z]] <https://www.shtml.jp/mojibake/english.html>


[240] 
[CITE@en[1551276 - (chardetng) Autodetect legacy encoding on unlabeled pages]], [TIME[2025-11-23T02:33:03.000Z]] <https://bugzilla.mozilla.org/show_bug.cgi?id=1551276>

[241] 
[CITE@en[Security: ASCII can be autodetected as ISO-2022-JP '''['''40089450''']''' - Chromium]], [TIME[2025-11-23T03:27:53.000Z]] <https://issues.chromium.org/issues/40089450>

[242] >>241 [CITE[Firefox]] の開発者が [[ISO-2022-JP]] を自動判定するのは[[セキュリティー]]上の問題だと主張し、
[CITE[Chrome]] に判定から除外させた回。ところが [CITE[Firefox]] 
は今でも [[ISO-2022-JP]] と判定している。 [TIME[2025-11-23T03:29:38.400Z]]


** 決定に使う入力バイト列の長さと範囲

[SEE[ [[資源ヘッダー]], [[sniffing]], [[encoding sniffing algorithm]] ]]


* 出所とロケール情報による推測

[138] 
判定したい[[バイト列]]の出所 (例えば取得に使った [[URL]] の [[TLD]])
や関係する[[ロケール]]系の情報が[[文字コードの決定]]に使われることがあります。

[86] 
利用し得る情報の例:

- [158] [[バイト列]]の取得に使った情報
-- [139] 取得を始めるために使った [[URL]]
-- [161] [[リンク元]]の [[URL]]
-- [159] [[リンク元]]の[[言語情報]]
-- [160] [[リンク元]]の[[文字コード]]情報 ([[環境符号化]]ほど信用できないもの)
- [146] [[バイト列]]に付随するメタ情報
-- [142] 実際の取得に使った [[URL]] (c.f. [[リダイレクト]])
-- [184] 実際の取得に使った[[ファイル名]]
-- [183] 実際の取得に使った [[Internet Archive]] の [[URL]]
に含まれる原 [[URL]]
-- [165] [CODE[From:]] の[[メールアドレス]]
-- [166] [CODE[Newsgroups:]] の[[ニュースグループ]]
-- [167] [[IRCサーバー]]の[[ドメイン名]]
-- [168] [[IRC]] の[[チャンネル]]
-- [140] [CODE[Content-Location:]]
-- [147] [CODE[Content-Language:]]
-- [192] [CODE[Content-Disposition:]] の [CODE[filename]]
-- [193] [[書庫ファイル]]の格納[[ファイル]]の[[ファイル名]]
-- [151] [[書庫ファイル]]の格納[[ファイル]]の [[OS]] 情報
-- [152] [[書庫ファイル]]の格納[[ファイル]]の作成[[アプリケーション]]情報
-- [162] 兄弟[[バイト列]]の情報
--- [163] 同じ[[書庫ファイル]]の他の[[ファイル]]の[[ファイル名]]とその[[文字コード]]
--- [164] [[RFC 822メッセージ]]の[[ヘッダー]]と[[本体]]の[[文字コード]]
-- [185] [[バイト列]]が[[添付ファイル]]であるときそれが添付された元[[メッセージ]]や元[[メッセージ]]の主たる[[部分]]の情報
--- [186] [[実体]]の[[文字コード]]
--- [190] [[実体]]の [CODE[Content-Language:]]
--- [191] [[実体]]の[[文書要素]]の[[要素の言語]]
- [153] 利用環境に関する情報
-- [154] [[Webブラウザー]]の[[言語]]設定
-- [155] [[プラットフォーム]]の[[ロケール]]設定
--- [156] [[POSIXロケール]]
--- [157] [[ANSIコードページ]], [[OEMコードページ]]

[141] [[URL]] や[[ファイル名]]や[[ドメイン名]]から利用できる情報の例:

- [143] [CODE[file:]] かどうか
- [145] [[TLD]]
- [148] [[URL]] の[[先頭一致]]
- [149] [[言語]]を表す[[拡張子]]
- [150] [[文字コード]]を表す[[拡張子]]

[169] 
利用方法:

- [170] [[文字コード指定メニュー]]の優先表示選択肢の絞り込み
- [171] [[頻度解析等の手法]]の候補の絞り込みや重みの割当
- [172] 他のどの方法でも決定できないときの既定値の選択


-*-*-

[236] 
[CITE@en[845791 - Gather telemetry about the necessity of the Russian and Ukrainian encoding detectors]], [TIME[2025-11-23T02:17:27.000Z]] <https://bugzilla.mozilla.org/show_bug.cgi?id=845791>


[239] >>236 [CITE[Firefox]] が[[キリル文字の文字コード]]の判定を廃止する[[非互換変更]]を企て失敗した回


** TLD の利用

[204] 
[[頻度解析等の手法]]は[[バイト列]]だけでは似た構造の[[文字コードの判定]]に失敗することが少なくないので、
他の情報を補助的に使うことが試みられています。 [[TLD]] 
は特に有力な情報源と考えられています。

[205] 
[[ccTLD]] は、一部の国際的に商業化されたものを除けば、
ほぼ当該[[地域]]で使われています。従って当該[[地域]]の一般的な[[文字コード]]が使われている可能性が、
他の[[地域]]の[[文字コード]]よりずっと高いと考えられます。

[SEE[ [[TLDによる文字コード判定の補助]] ]]

[215] 
ただ、この情報は飽くまでも補助に過ぎません。

- [216] [[IPアドレス]]によるアクセスでは [[TLD]] を使えません。
-- [217] [[逆引き]]や [[IPアドレス]]の割当国データベースに基づく推定も可能ではありますが、
実行コストの高い演算なので、判定ヒントを得るためにしては費用対効果に見合うか疑問です。
- [218] [[gTLD]] では [[ccTLD]] による推定を使えません。
--[219] 昔も今も [[ccTLD]] 以外の [[TLD]] は全世界的によく使われています。
- [220] [[ccTLD]] でも国外で多く使われている事例がいくつもあります。
-- [222] 例えば [CODE[.tv]] は国外のテレビ業界で使われがちです。
-- [221] [[ccTLD]] を使う手法はこうした用途が多い [[ccTLD]] を除外しています。
[SEE[ [[TLDによる文字コード判定の補助]] ]]
--- [223] しかし完璧ではなく、国外利用が多くても除外されていないことがあります。
--- [224] 国内利用についても [[ccTLD]] に基づくヒントを供給できなくなる弊害があります。
- [225] [[正書法]]改革や表記法の対立、内戦などを抱えている国では、
[[ccTLD]] のヒントが機能しにくいことがあります。


[226] 
[[TLD]] は若干の傾斜を与えたり、最終的に判断がつかなかったときの既定値を決めたりするのに使うのがいいのでしょう。
[[TLD]] に基づき候補を絞り込んでそれ以外を除外したりするのは避けておくのが無難です。

[227] 
逆に言うなら、

- [228] [[TLD]] からのヒントがなくてもそれなりに高精度で判別できるようにすること、
- [229] [[文字コード指定メニュー]]のような[[利用者]]が上書きする手段を用意すること、

の'''両方'''が必須です。




- [243] 
[CITE@en[977540 - Don't apply detectors to foreign domains]], [TIME[2025-11-23T03:42:45.000Z]] <https://bugzilla.mozilla.org/show_bug.cgi?id=977540>
-[237] 
[CITE@en[1543077 - Japanese auto-detect no longer work on some generic (i.e. language neutral) TLDs]], [TIME[2025-11-23T02:20:01.000Z]] <https://bugzilla.mozilla.org/show_bug.cgi?id=1543077>

[238] >>237 [CITE[Firefox]] が
[[gTLD]] での[[文字コードの判定]]を廃止する[[非互換変更]]を企て失敗した回

-*-*-

[187] 
[[HTTP]] [CODE[charset]] や [[HTML]] [CODE[<meta charset>]] などで指定された[[文字符号化]]は、
[CODE[.mn]] の場合、次のように置換するべきです。
[SEE[ [[ロケール等による文字コード判定の補助]] ]]


- [234] [[IBM866]] → [[x-MNS4329]]
- [246] [[windows-1251]] → [[x-MNS4330]]
- [247] [[x-mac-cyrillic]] → [[x-MNS4331]]

** ロケールの利用

[87] [[プラットフォーム]]の[[ロケール]]や[[言語]]の情報が[[文字コードの判定]]のヒントに使われることがあります。

[195] [CITE[ced]] は[[利用者インターフェイス]]の[[言語情報]]があればヒントとして使うことがあります。
[SRC[>>43]]

[38] [[subtitle]] の[[文字コードの判定]]に[[言語情報]]が使われることがあります。
[SEE[ [[ロケール等による文字コード判定の補助]] ]]

[39] [[ZIPファイル]]の[[文字コードの判定]]の補助または既定値の決定に
[[POSIXロケール]]が使われることがあります。
[SEE[ [[ZIPファイルの文字コード]] ]]

[REFS[

- [43] 
[CITE@en[[[compact_enc_det]]/compact_enc_det/compact_enc_det.cc at master · google/compact_enc_det · GitHub]], [TIME[2025-05-19T15:36:17.000Z]] <https://github.com/google/compact_enc_det/blob/master/compact_enc_det/compact_enc_det.cc#L2059>

]REFS]

-*-*-

[178] 
[[HTML]] や[[テキストファイル]]の [[navigate]] では、
他の方法で決められないときの[[既定値]]が[[ロケール]]依存となっています。
[SRC[>>177]]

[179] 
より正確に言えば、[[実装定義]]または[[利用者]]指定の既定の文字符号化とすると定められています。
[SRC[>>177]]
現実的には[[利用者の言語]]から決めることになります。

[180] 
制御された環境や文書の[[符号化]]を予め決められる環境では、 [[UTF-8]]
を[[既定値]]とするのが[RUBYB[よい][suggested]]とされます。
例えば新しい[[ネットワーク]]の専用の[[利用者エージェント]]ではそうできると述べられています。
[SRC[>>177]]

;; [181] 具体的にそのような事例があるのかは不明です。
[[仕様書]]としては可能性を狭めないために「新しいネットワーク」
のようなものを想定しているのでしょうが、
現実的にそうしたものが大々的に導入される機会があるかは不透明です。
(例えば [[HTTPS]] や [[HTTP/2]] への移行でも、[[サーバー]]と[[内容]]は従来のままなので、
切り替えの機会とはできなかったわけで。)
特定の[[イントラネット]]や新しい種類の端末の専用ネットワークでも、
わざわざ既定値を変えるための設定や実装の変更よりは
[[HTTP]] [CODE[charset]] の指定を徹底させる方向性の方が楽そうで。


[182] 
それ以外の環境に対しては、
[[利用者]]の[[ロケール]]が[[利用者]]がよく見る[[Webページ]]の[[自然言語]]や[[符号化]]と相関があると考えられるため、
[[ロケール]]に[RUBYB[典型的には依存][typically dependent]]して既定値が定まるとされます。
[SRC[>>177]]
[SEE[ [[利用者の言語]], [[ロケール依存の既定の文字コード]] ]]


;; [194] [[UTF-8]] は[[頻度解析等の手法]]で高い確率で判定可能です。
であるなら [[UTF-8]] を既定値にするよりも、
既定値は [[Web]] 初期の[[文字コードの指定]]の慣習が無かった時代の
[[Webサイト]]をより良く救済できる可能性が高い値を選ぶのが良いと考えられます。



[REFS[

- [177] 
[CITE@en-US-x-hixie[HTML Standard]], [TIME[2025-11-04T10:59:41.000Z]], [TIME[2025-11-09T05:55:50.836Z]] <https://html.spec.whatwg.org/#determining-the-character-encoding>

]REFS]


[235] [CITE@en[Encoding detector causing compat issues '''['''41301730''']''' - Chromium]], [TIME[2025-11-23T02:10:48.000Z]] <https://issues.chromium.org/issues/41301730>

>I'm not sure when exactly Chromium diverged from WebKit, but the status prior to M55 (for several years) is that Chromium, by default, did no sniffing whatsoever and just used a system locale default.  Secondly, if the user ever clicked "Autodetect" in the encoding menu, this acted as a permanent setting, and in that case ICU autodetector would run on 100% of page loads, overriding all headers, and supporting the entire set of ICU encodings.
>
Starting at M55, we removed all menus and all influence of system locale, and started to run CED autodetector by default but only affecting pages without headers.
>
To my knowledge, Chromium has never shipped a Japanese-specific sniffing configuration.


** その他の試み

- [68] [CITE@en-US[Encode::Detect::Upload - Attempt to guess user's locale encoding from IP, HTTP_ACCEPT_LANGUAGE and HTTP_USER_AGENT - metacpan.org]], [TIME[2025-06-16T10:29:46.000Z]] <https://metacpan.org/pod/Encode::Detect::Upload>

[69] >>68 [CODE[Accept-Language:]], [CODE[User-Agent:]] ([[OS]]), 
アクセス者の [[IPアドレス]]を使って[[文字符号化]]を推定する。
平成25年。






* 符号構造や出現頻度などによる総合的な推測

[2] 
[[文字コードの指定]]の構文が存在しない [WEAK[(または利用されていない)]] 
[[文字列]]の[[バイト列]]があるとき、
その[[文字コード]]は[[バイト列]]それ自体から推定することになります。

[377] 
この推定は、どうしても不確実性が伴います。様々な手法が開発され、
それらを組み合わせることで精度が高められてはいますが、
いずれの手法も絶対的とは言えません。

[378] 
この種の技法は3通りに大別できます。

- [379] [[符号構造]]に基づく判別
- [380] 典型的バイト列による推測
- [381] 統計的手法による推測

この3種は必ずしもきっちりと分類できるものではなく、
境界的技法もありますし、実装上は組合せて実現されることもあります。

[EG[

[382] 例えば[[符号構造]]上あり得ない[[バイト]]は条件分岐のような形で単独で判定することもできますし、
統計的手法による期待出現頻度 0 と記述して計算することもできます。
どのように実現するかは実装戦略上の判断になります。

]EG]


[383] 
各技法の詳細はこの後の各節を参照。

-*-*-

[230] 
[[平成時代]]初期 ([[西暦1990年代]]) には [[Web]] 等で[[文字コード]]情報のない[[テキストファイル]]が[[国]]や[[言語]]の境を超えて多く流通するようになり、
[[文字コードの判定]]の手法の研究と実装が各所で行われました。

[5] 
特に[[日本]]と[[キリル文字]]圏では、
複数の[[文字コード]]が同程度に広く使われていたために[[自動判定]]が重宝されていました。

[331] 
[[21世紀]]に入ると単一の実装で全世界に対応する[[多言語]]対応手法の普及が進みましたが、
[[文字コードの判定]]も単一地域の[[利用者]]が遭遇する[[文字コード]]体系に限らず、
全世界の[[文字コード]]体系を対象とする必要が生じ、複雑化しました。

[332] 
逆に [[Web]] では [CODE[charset]] [[引数]]等による明示的な指定が普及し、
追って [[UTF-8]] への統合が進んだことで、
[[バイト列]]からの推定による[[文字コードの判定]]の出番は減少しました。

[333] 
とはいえ、過去のデータや[[イントラネット]]、
[[ZIPファイル]]、 [[CSV]]、 [[subtitle]]
など旧来の[[文字コード]]が混在する領域も依然として残っており、
[[文字コードの判定]]の技術の需要が失われたわけではありません。


** 対象とする符号


[384] 
判定器は、対応する[[符号]] ([[文字コード]]体系) を決める必要があります。

[385] 
多くの[[符号]]に対応している判定器は便利ですが、
どんな判定手法も完璧でない以上、
誤判定とのトレードオフになることには注意が必要です。
対応[[符号]]数が多いほど誤判定のリスクが高まります。
似た構造の[[符号]]が含まれると判定問題の難易度が急激に上がります。

[386] 
判定器の実装戦略にもよりますが、一般に[[符号]]数が増えれば増えるほど、
判定速度は劣化し消費メモリー量は増大します。
判定に必要な計算や参照するデータが多くなるためです。

[387] 
従って判定器の実装者は適用対象の分野をよく分析し、
必要な[[符号]]を過不足なく選ぶ必要があります。
[SEE[ [[Webにおける文字コード]], [[ファイル名の文字コード]] ]]

[EG[

[423] 
便利な工具として使える独立した判定器なら、多少処理に時間がかかっても、
あらゆる候補を徹底的に分析して回答を出すことに意味があるかもしれません。

[424] 
一方で [[Webブラウザー]]に組み込まれた判定器なら、
[[文字コードの判定]]は数多くの処理の一部に過ぎませんから、
時間をかけるより高速に動作することが、
多くの検証用データを保持するより小さな実装であることが求められます。

]EG]

[EG[

[425] 
[[ZIPファイル]]の[[ファイル名の文字コード]]のための判定器は、
およそ出現するとは考えにくい [[UTF-16]] や [[ISO-2022-JP]]
のような[[符号]]を最初から候補から除外しておく方が何かと良さそうです。

]EG]

[388] 
[[セキュリティー]]にも注意が必要です。
例えば、本来ただの [[ASCII文字列]]と判断されるべきものに
[[UTF-7]] を注入し、 [[UTF-7]] 
と判定させることで任意プログラムを実行させるような攻撃手法があり、
[[UTF-7]] という[[符号化方式]]自体が危険と認識され忌避されるようになった事例があります。
[[文字コードの判定]]という演算が行われること自体が相応しくない状況もあれば、
[[文字コードの判定]]で特定の[[符号]]を認識することに問題がある状況もあり、
[[符号化方式]]の側に汚名が着せられるケースもあり、
ケースバイケースの判断が必要です。
[SEE[ [[文字のセキュリティー]], [[Webセキュリティー]] ]]

;; [389] 
特定の[[符号]]と判断された場合に機能制限モードに切り替えるとか、
外部的指定が無く[[文字コードの判定]]が必要とされたときに機能制限モードに切り替えるとか、
対策の仕方もケースバイケースです。

** 符号構造に基づく判別

[231] 
[[文字コードの判定]]の基礎的な技法の1つが[[符号構造]]を利用するものです。


[58] 
[[平成時代]]中頃までの古典的な方法では、
[[文字符号化]]によって[[符号]]の構造が異なることを利用し、
ある[[文字コード]]体系で出現する[[符号]]かそうでないかという構造的知識を主に使っていました。
しかしこの方法単独では[[符号]]構造が重複する領域で互いの区別が付きづらく、
あまり精度が上げられませんでした。
ただ、実装が容易ではあるので、幅広く用いられましたし、現在でも使われることは珍しくありません。

[EG[

[59] 例えば[[シフトJIS]]と[[日本語EUC]]は第1バイトに使われる[[バイト]]、
第2バイトに使われる[[バイト]]の範囲がそれぞれ違っていますので、
その範囲に収まるかによってどちらか判断できることが多いです。
しかし完全に重なる部分もあるため、そのような[[符号]]ばかりだと正しく判定できません。

[60] 
また、[[半角カタカナ]]を利用すると両者の重なる領域が著しく増えるため、
誤判定が多くなり、頻繁に[[半角カタカナ]]の[[文字化け]]を目にすることになります。
これは[[半角カタカナ]]が嫌われる大きな要因の1つにもなっていました。

]EG]

-*-*-

[334] 
[[多バイト符号]]の判定では[[符号構造]]を理解し区別することが基礎となります。

[336] 
ただし各[[符号]]の構造は共通の部分もありますから、完璧ではありません。

[339] 
特に
[[EUC-JP]],
[[gb18030]] (= [[EUC-CN]]),
[[EUC-KR]] (= [[UHC]])
はいずれも [[EUC]] を採用しているので、基本的な文字が収容される [[CS1]]
が同一の構造となっています。

[337] 
また、 [[EUC-JP]] の2バイト文字の少なくない数が、 [[Shift_JIS]]
の1バイト文字 ([[半角カナ]]) 2つ分に当たります。

[338] 
こうした同一部分は判定に使えません。
同一部分を除いた残りの固有部分で、どの[[符号]]かがわかります。
ところが基本的な文字が同一構造の部分にあると、
固有部分が[[文字列]]に含まれているとは限らないので、
判定できないことになります。

[340] 
狭義の構造だけで判断できなくても、
空き領域で判断できることがあります。
[[2バイト符号]]には使われていない領域も多いですが、
各[[符号]]で少しだけ空きの範囲が違います。
空きが含まれていれば、その[[符号]]は候補から除外できます。

[341] 
ただし、空き領域が[[外字]]として利用されてきた歴史があることには注意が必要です。
空き領域が出現したからといってただちに除外すると、正解も除外されてしまうおそれがあります。

-*-*-

[335] 
1バイトの[[7ビット符号]]や[[8ビット符号]]の判定では、
[[符号平面]]のほとんどの[[ビット組合せ]]に有効な[[文字]]が割り当てられてしまっているため、
[[符号構造]]とその利用からの判断の余地はそれほど大きくありません。

[342] 
それでも一部の[[符号]]には空き領域があるので、それが出現すれば、
その[[符号]]は候補から除外できます。

-*-*-

[343] 
1バイトの[[8ビット符号]]の [[CR]] や[[多バイト符号]]の1バイトの未使用の[[ビット組合せ]]は、
基本的には使用されていません。極稀に[[外字]]等で利用されることがあるものの、
[[Web]] 等で流通するデータに利用されることはまずないと考えられます。
これらは[[多バイト符号]]の先頭バイトに使われる領域なので、
当該[[多バイト符号]]以外を除外する条件として使えます。

[344] 
[N[0x7F]] も条件は近いのですが、ほとんどの[[符号]]で使われておらず、
[[多バイト符号]]の1バイト目にも2バイト目にもまず出現しないので、
どう扱ってもかわりありません。

-*-*-

[345] 
[[CL]] のうち、[[空白]]等
([ [N[0x09]], [N[0x0D]] ], [N[0x1A]])
と
[[ISO/IEC 2022]] で使う[[制御機能]] 
([N[0x1B]], [N[0x0E]], [N[0x0F]])
を除いた部分も、通常の[[文字列]]に出現することはまずありません。

[347] 
これらも、
[[ASCII]]
の系譜の[[文字コードの判定]]にはほとんど関与しません。

[348] 
ただし、
[[VISCII]]
等では[[図形文字]]を割り当てていること、
[[OEMコードページ]]では[[図形文字]]を呼び出すために使われたこと、
には注意が必要です。

[346] 
[[文字コードの判定]]の実装の中には[[バイナリー]]という判定結果を返すことができるものもあります。
この領域が出現し、 [[VISCII]], [[UTF-16]] 等でないなら、[[バイナリー]]と判断できます。

[349] 
[[文字コードの判定]]の実装が[[バイナリー]]をどう扱うかは悩ましい問題です。
用途と実装戦略次第のところではありますが、明らかに[[文字列]]ではない[[バイト列]]の処理を延々と続けても仕方がないと考えると、
[[バイナリー]]、あるいは「結果無し/不明」という回答を用意して、
それが確定的になれば早々に処理を打ち切るという選択肢もあることでしょう。

-*-*-


[78] 
対応している[[符号化]]を順番に試してエラーにならなかったものを採用するという''だけ''の実装を
「文字コードの判定」だと称しているものがたまにあります。
このような方法は[[符号構造]]がまったく違う[[符号]]の区別になら使えますが、
多くの[[8ビット符号]]の区別が不可能です。

[257] 
このような原始的な手法では
[[Shift_JIS]] と [[EUC-JP]] の区別すら完全にはできないことが[[日本]]では古くからよく知られています。

;; [79] [[符号構造]]が限定される場合なら、その限定される特徴で判定したほうが高速かつ確実なことが多いので、
この手法が役に立つことはほぼないといっていいでしょう。




*** UTF-8

[129]
[[UTF-8]] はかなり確実に判定できることが知られています。
[SEE[ [[頻度解析等の手法]] ]]

[288] 
[[UTF-8]] の2バイト以上の[[バイト列]]が含まれ、それ以外に[[非ASCII文字]]が含まれないなら、
[[UTF-8]] と判定してほぼ間違いありません。

[285] 
ただし[[8ビット符号]]の領域を使っている以上誤判定の可能性が皆無ではありません。

[287] 
[CITE[ced]] は4種類の2バイト列を [[UTF-8]] ではなく [[windows-1252]]
に加重する例外条件を持っています。 [SRC[>>286]]

[REFS[

- [286] 
[CITE@en[[[compact_enc_det]]/compact_enc_det/compact_enc_det.cc at master · google/compact_enc_det · GitHub]], [TIME[2025-11-24T08:13:14.000Z]] <https://github.com/google/compact_enc_det/blob/master/compact_enc_det/compact_enc_det.cc#L83>

]REFS]

*** [CN[BOM]]

[1] 
[[Web]] では[[歴史的事情]]により [CN[BOM]] の存在がかなり重視されています。
[SEE[ [[encoding sniffing algorithm]] ]]

[57] 
[CN[BOM]] に対応した仕様や実装でも、どの[[文字符号化]]の [CN[BOM]] を検知するかはかなりブレがあります。
現在の [[Web]] は [[UTF-16]] と [[UTF-8]] に限定しています。
過去の [[Web]] や [[Web]] 以外の実装はそれ以外にもいろいろなものに対応していたり、
いなかったりします。

[132] 
[CN[BOM]]
による検知は常に適用できるものではなく、使わない場合もあります。
例えば[[ファイル]]全体ではなく[[プロトコル要素]]として用いられる[[文字列]]片では
[CN[BOM]] が認められていない場合が一般的であり、その場合たとえ [CN[BOM]]
のように見えたとしてもそれは本来の[[文字列]]の先頭です。
[[文字コード]]の判定には使えません。

[EG[
[133] 
[[ZIPファイル]]の[[ファイル名]]の[[文字コードの判定]]では
[CN[BOM]]
検査を行いません。
]EG]


*** ISO/IEC 2022 指示シーケンス

[355] 
[[ISO/IEC 2022]] の[[指示シーケンス]]は自己識別的に[[符号化文字集合]]を特定する情報を含んでおり、
[[文字コードの判定]]上極めて重要です。

[356] 
ただし実務上いくつか注意が必要です。

- [357] [CN[ESC]] が含まれていることだけで [[ISO/IEC 2022]] と判定するのは危険です。
[[CSI]] のために使っているもの、
[[ISO/IEC 2022]] と異なる非標準の用法、
破損データなどの場合も想定する必要があります。
- [358] [[ISO/IEC 2022]] の中にも
[[ISO-2022-JP]] など完全に自己記述的な[[指示シーケンス]]を含む[[符号]]と、
そうでない[[符号]]があります。
前者なら[[指示シーケンス]]を決定的根拠とできますが、
後者は追加の情報がないと確定できません。
- [359] 
具体的には次のような[[符号]]に特に注意が必要です。
-- [360] 
[[IE]] が対応していた [[ISO-2022-JP]] と[[シフトJIS]]
の[[混合][文字コードの混合]]など
[SEE[ [[ISO-2022-JP]] ]]
-- [361] 
[[ISO-2022-JP]] に[[8ビット符号]]としてまたは [CN[SI]]/[CN[SO]]
により[[半角カナ]]を追加した独自仕様の[[符号]]
-- [362] 
[[ISO-2022-JP]] や[[シフトJIS]]に [CN[ESC]]
を使った独自構文で[[絵文字]]を追加した[[符号]]
-- [363] 
[[汎用機]]等で使う [CN[ESC]] を使った独自構文で[[漢字]]と [[JIS X 0201]]
を区別する[[符号]]
-- [364] 
[[大韓民国]]でよく流通していたという[[指示シーケンス]]の無い [[ISO-2022-KR]]
-- [365] 
[[ANSIエスケープシーケンス]]を含んだ[[ソースコード]]や[[バッチファイル]]など
- [366] [[私用]]の[[終端バイト]] [[Fp]]
や一部[[端末]]の非標準の[[終端バイト]]の[[指示シーケンス]]を使った[[符号]]
[SEE[ [[指示シーケンス]], [[Fp]] ]]
は、
それが何を表すのか判定が必要になる場合があります。
-- [367] 公開データとして流通しているものは [[Mule]] 系の [[Fp]]
の場合が多いようですが、それ以外もあり、一部は衝突しているので要注意です。
- [368] 
[[復号器]]が完全な [[ISO/IEC 2022]] の実装ではない場合は、
たとえ完全に自己記述的な[[符号]]であったとしても、
どんな[[指示シーケンス]]が利用されているか検査が必要となります。
-- [369] 
例えば 
[[ISO/IEC 2022]] 全体の[[復号器]]がない環境で、
[[ISO-2022-JP-2]]
と
[[ISO-2022-JP-3]]
の[[復号器]]があるなら、両者は共通部分とそれぞれの固有部分があるので、
どちらの[[復号器]]が適切かの判断が必要となります。


*** 日本語文字コードの識別用符号列


[370] 
[[日本語圏]]では[[シフトJIS]]と[[日本語EUC]]の区別のために特徴的な文字列を挿入する手法が開発されてきました
(>>135)。

[371] 
こうした手法は [[Shift_JIS]] と [[EUC-JP]] の区別にはそれだけで有益であったとしても、
それ以外の世界の[[文字コード]]が候補となるとき、必ずしも十分な根拠にならないこともあります。

[372] 
しかしせっかく[[著者]]が提供してくれているヒントを判定器が無視するのももったいないのであり、
[CN[BOM]] や[[指示シーケンス]]ほどの確実性は無いとしても、
それに準じた重要情報として利用することが期待されます。






*** gb18030 の特徴的な符号列

[275] 
[[gb18030]] の4バイト符号は、第1バイトと第3バイトに[[右]]の[[バイト]]が使われ、
第2バイトと第3バイトは [[ASCII数字]]の[[バイト]]が使われるというかなり独特の構造をしています。
主要な[[多バイト符号]]で[[ASCII数字]]を第2バイトに使うのは [[gb18030]]
だけです。
各種の[[8ビット符号]]でこうした並びが出現することもあるでしょうが、
特殊な用例に限られるのではないかと思われます。
そこでこうした並びを数えて、
[[gb18030]]
と判定する有力な根拠として使うことができます。



*** 判定条件からの逸脱の扱い

[350] 
ある[[符号]]で使わない[[バイト]]の出現でその[[符号]]を候補から除外することは、
ときに正解の[[符号]]まで過剰に除外してしまうおそれがあります。

[351] 
[[空き領域]]が出現した候補を除外すると、[[外字]]が入ったデータを正しく判定できない場合があります
(>>341)。その[[符号]]における空き領域の利用実態を勘案して出現頻度の閾値を決めるなど、
曖昧な判断が望ましいことがあります。

[352] 
[[符号構造]]から逸脱した候補を除外すると、破損データを正しく判定できない場合があります。
古いデータには特に言えることですが、
生成や転送の過程の何らかの問題で多バイト文字の一部が破損したり、
関係ないデータが混入したり、
といった理由で通常の[[符号構造]]に沿わない[[バイト]]が出現することが、
ままあります。一度の違反で即決せず、
[[バイト列]]の全体の傾向から総合的に判断するべき場合があります。

[353] 
判定条件を弱めれば弱めるほど不規則データへの耐性は高まりますが、
他の[[符号]]と誤認する可能性も高めてしまうことになります。
あらゆる破損に対応することは原理的に不可能で、
どこかで線引きが必要です。

[354] 
正常データのほとんどすべてを正しく判定できつつ、
異常データもできればなるべく作成者の想定に近いものと判定できることが好ましいと考えられますが、
具体的にどのような状態を良しとし、
どのようにそれを実現するか、は判定器の適用分野と実装戦略次第になります。




** 典型的バイト列による推測


[249] 
[[符号]]や[[応用]]に依存した「ありがち」な[[バイト列]]のパターンが出現することがあります。

[250] 
どれくらい決定的な根拠にできるかはケースバイケースで、
他の[[符号]]との区別や「ありがち」な度合いによって調整が必要となります。



*** 8ビット符号の特徴的な符号列


[265] 
かなり多くの[[Webページ]]が[CH[©]]を使った[[著作権表記]]を持っています。
[CH[©]]の前は空白か[[タグ]]で、
[CH[©]]の後は空白か[[タグ]]か、[[年号]]か[[著作権者]]が来ます。

[266] 
[[windows-1252]] やいくつかの[[文字コード]]体系で [N[0xA9]] に [CH[©]]
があります。 >>265 のような[[バイト列]]のパターンを発見できれば、
そうした[[文字コード]]体系である可能性が相当高くなります。

[269] 
[N[0xA9]] は [[Shift_JIS]] で[[半角カナ]]の [CH[ゥ]] に当たります。
幸い [CH[ゥ]] は直前に[[カタカナ]]が来ることがほとんどで、 >>265 
のようなパターンで出現することはまずありません。
[[Shift_JIS]] でないことを示す徴証として使うのが良いと考えられます。

[318] 
他の[[多バイト符号]]では第1バイトに使われることがありますし、
[[Shift_JIS]] でも第2バイトには使われることがあります。
前後が[[空白]], という条件が重要になります。
多くの[[多バイト符号]]だと第2バイトに [CH[<]] や [CH[>]] が来ることもないので、
[[タグ]]も[[空白]]と同等に扱えます。
それ以外だと徴証としては少し弱くなります。

[317] 
[[windows-1252]] やいくつかの[[文字コード]]体系で [N[0xAE]] に 
[CH[®]] があります。
[N[0x99]]
に
[CH[™]]
があります。これらは語末に出現します。

[319] 
[[英数字]]の後に[[半角カナ]] [N[0xAE]] 
が1つだけ出現して[[空白]]が来ることはほとんどないので、
[[Shift_JIS]] ではない可能性が高いと判断できます。

[320] 
しかし [N[0xAE]] や [N[0x99]] は[[多バイト符号]]の第2バイトになることがあるので、
[[非ASCII文字]]の後に [N[0xAE]] や [N[0x99]]
が来るケースでは注意が必要です。

[EG[

[321] 
[CITE[ced]] は 「NESTLÉ®」 を [[UTF-8]] と誤認される [[windows-1252]] 
の実例として挙げています。この例のように [[Shift_JIS]] 等の他に
[[UTF-8]] としても正当なバイト列になり得ることがあるので注意が必要です。


]EG]

[267] 
他に[[非ASCII文字]]がなくても[CH[©]]や[CH[®]]だけが[[非ASCII文字]]として含まれることが、
[[欧米]]や[[中央アジア]]をはじめ、世界的によく見られます。
そうした場合にこれを [[Windows-1252]] と判断することが重要になってきます。


;; [268] [[言語]]モデルによる判定は [[letter]] だけを使いがちで、
[CH[©]]
のような記号が除外されていて判定に使われず、[[文字化け]]してしまうことがあります。


[270] [CITE[chardetng]] などがこうしたものを
[[windows-1252]] と判定する条件を組み込んでいます。
[SRC[>>289]]



;; [290] ただし [CITE[chardetng]] はそれでも 
[CH[©]]
を
[[ISO-8859-2]] と誤認しがちです。
[[ISO-8859-2]] との区別についてはわざわざ注釈で言及があります [SRC[>>289]]
ので、意識して設計されているはずですが、それでも取り扱いが難しいということなのでしょう。

[EG[

[330] 
>>329
は
「Copyright ©1997,」
の [CH[©]] 1文字 ([N[0xA9]])
だけが[[非ASCII文字]]です。
[CITE[ced]] は正しく判定しますが、
[CITE[chardetng]] は [[ISO-8859-2]] と誤認します。

[REFS[

- [329] 
[CITE[Open Society-Georgia Foundation ([[OSGF]])]], [TIME[2025-11-30T03:20:04.000Z]] <https://web.archive.org/web/19981202173516id_/http://www.osgf.ge/>

]REFS]

]EG]


[580] 
[CITE[chardetng]] はこの他にも[[序数標識]]や [CH[’]]
に関係するいくつかのパターンで特殊処理を持っています。
[SRC[>>289]]




[REFS[

- [289] 
[CITE@en[[[chardetng]]/src/lib.rs at main · hsivonen/chardetng · GitHub]], [TIME[2025-11-24T08:19:16.000Z]] <https://github.com/hsivonen/chardetng/blob/main/src/lib.rs#L58>
- [295] 
[CITE@en[[[chardetng]]/src/lib.rs at main · hsivonen/chardetng · GitHub]], [TIME[2025-11-24T08:34:54.000Z]] <https://github.com/hsivonen/chardetng/blob/main/src/lib.rs#L450>


]REFS]


*** 価格

[322] 
[[windows-1252]] などいくつかの[[コードページ]]の [N[0x80]] は [CH[€]]
です。[[通貨記号]]の後に[[ASCII数字]]が続くなら、
[[価格]]の表記と考えられ、
その[[文字コード]]体系であることのヒントとして使えます。

;; [323] [[言語]]モデルによる判定は [[letter]] だけを使いがちで、
[[通貨記号]]や[[数字]]が除外されていて判定に使われず、[[文字化け]]してしまうことがあります。

[324] 
[N[0x80]] は主要な[[多バイト符号]]の第1バイトには使われないので、
空白の後などで重要なヒントとして使えます。
しかし第2バイトに使われることはあるので、注意が必要です。

[325] 
[[windows-1252]] の [N[0xA4]] など他の[[通貨記号]]は[[多バイト符号]]の第1バイトや第2バイトや、
[[Shift_JIS]] の[[半角カナ]]に使われることがあるので、注意が必要です。

*** 罫線素片

[326] 
多くの [[OEMコードページ]]は[[罫線素片]]等の [[CUI]] 
描画のための部品[[文字]]を多く持っています。
これらは通常の文章には出てこないことが多いですが、図表などで使われることもあります。

[327] 
こうした文字が1つだけ孤立して出現することはまずないので、
負のヒントとして使うことができます。


[328] 
ただし縦線はそこだけ見ると前後に別の文字が来る、孤立した文字に見えますから、
単に前後が[[罫線素片]]でないというだけでは足りず、少し工夫が必要です。
前後の行との結合を検査すれば確実ですが、
そこまでせずとも、
他に横線 ([[罫線素片]]の連続) があるなら同様に[[罫線素片]]とみなしてよく、
他に横線がどこにもないなら負のヒントとみなすのがいいかもしれません。


[251] 
[[ファイル名]]に出現することもまずないので、
[[OEMコードページ]]が使われることが多い
[[ZIPファイル]]の[[ファイル名]]の[[文字コードの判定]]では1個の出現だけでも強力な負のヒントになります。


*** 仮名

[510] 
[[日本語]]の[[文章]]には[[仮名]]が頻出します。

[511] 
どの[[文字コード]]体系でも[[仮名]]は連続して特定の範囲に配置されていますから、
[[仮名]]が使われた文章は特徴的なバイト列になります。

[512] 
[[Shift_JIS]] と [[EUC-JP]] との区別や、各国の [[EUC]]
との区別に非常に便利な特徴です。
[[日本]]では古くから使われてきました。
近年でも [CITE[chardetng]] が利用しています [SRC[>>252]]。

*** ハングル

[513] 
[[大韓民国語]]の日常的な[[文章]]は大部分が[[ハングル]]で表記されます。
[[漢字]]は例外的です。

[514] 
[[EUC-KR]] と [[gb18030]] や [[EUC-JP]] は基本構造が共通しているので、
一見すると区別がつかなそうですが、いくつか特徴があります。

- [515] [[ハングル]]は[[分かち書き]]され、
[[中文]]や[[日本語]]はされないので、[[語長]]で明瞭に区別できます。
- [516] [[日本語]]では[[仮名]]が有意に検出できます (>>510)。
- [517] [[EUC-KR]] の [[KS X 1001]]
では[[ハングル]]と[[漢字]]のブロックが分かれています。
[[ハングル]]の領域ばかりの出現でも区別できると
[CITE[chardetng]] は述べています。 [SRC[>>252]]



*** EUC-JP の特徴的な符号列

[271] 
[[EUC-JP]] の [[CS3]] は [[JIS X 0212]] ですが、
先頭付近のいくつかの[[区]]に[[ダイアクリティカルマーク]]付き[[アルファベット]]等が配置されています。
こうした[[文字]]の使われ方を想像すると、
[[欧州]]の[[言語]]の[[単語]]を表す通常の[[アルファベット]]の列の中に孤立して1つだけ混じることが多そうです。
2つ以上続くこともあるでしょうが、1つだけのことが多そうです。


[272] 
例えば [[ASCII文字]]に囲まれた [N[0x8F]] ([CN[SS3]]) と [[GR]] 
のバイト2つで構成される3バイトの列は、 >>271 の文字である可能性が高そうです。
各種の[[8ビット符号]]でもこのようなバイト列が出現することは考えられますが、
この特徴的な並びが意味のある[[言語]]の語を構成することは余り多くはなさそうです。
そこでこうした並びを数えて、
[[EUC-JP]]
と判定する有力な根拠として使うことができます。

[273] 
実際のところ [[EUC-JP]] でこれらの[[文字]]を使った (しかし一般の[[日本語文字]]はあまり使わない)
文章はそこまで多くないと思われます。
[[文字コードの判定]]のためのライブラリーのテストデータに含まれていることもあるのですが、
テスト用に変換して人工的に作った例文と思われます。

[274] 
よってあまり優先度は高くありませんが、簡単に対応できるならしておいても良いかなという感じでしょうか。


*** UTF-16 や UTF-32

[373] 
[[HTML]] をはじめとする[[機械可読]]の[[データ形式]]のほとんどは
[[ASCII文字]]を構文記述に使っています。
[[Unicode]]
では
[[ASCII文字]]が [ [CC[U+0000]], [CC[U+007F]] ]
に配置されているので、
[[UTF-16]] や [[UTF-32]]
では [N[0x00]] が規則的かつ大量に出現することになります。

[374] 
[[ASCII文字]]が使われていることが期待される
[[UTF-16]] / [[UTF-32]] の[[バイト列]]は、 
[CN[BOM]] がなくても 
[N[0x00]]
の数を数えることで高確度で判定できます。


[375] 
[[ASCII文字]]が少ない場合でも、近いブロックに配置された[[文字]]が並びがちという特徴を使えば、
[[UTF-16]] か [[UTF-32]] か [[ASCII]] 系かはそれなりの確度で判定できると思われます。

;; [376] しかしあまり需要が無いので、研究も実装もそれほどなされていないようです。

*** 改行

[636] 
[[Mac OS符号化]]であることの徴証の1つとして「[[改行]]が [CN[CR]] であること」が使える可能性がありますが、この性質を実用している判定器は見当たりません。実世界データでの検証の報告もなく、実効性は不明です。

-*-*-

[645] 
[[文字コードの判定]]と近接する問題に「[[改行コード]]の判別」があります。

[637] 
[[テキストファイル]]系の現代的な[[データ形式]]のほとんどは[[改行コード]]として [CN[CR]], [CN[LF]], [CN[CRLF]] のいずれもを認識するか、そうでないとしても[[空白文字]]として扱うので、[[改行]]の判別が必要になることはそれほど多くありません。

[638] 
[[改行コード]]の判定を主に必要とするのは[[テキストエディター]]の類で、どの形式であるかを認識し、新たな[[改行]]や保存時に使う[[改行]]を判定結果に設定することになります。

[639] 
あまり必要性の高くない単純な処理なので、
詳しく議論されている例を見かけません。具体的な実装方法としては、

- [640] 最初に発見したものを採用する
- [641] 全体を走査して最頻のものを採用する

...
のどちらかが一般的でしょうか。

[642] 
なお、[[行]]が長大または[[改行]]が存在しないファイルを読み込んだときに異常動作しない対策は必須となります。
([[テキストエディター]]は[[ファイル]]の全体を読み込むことが多いのでこの処理に特化した問題とはならないかも知れませんが。)

[643] 
[[ASCII]] の系譜のほぼすべての[[文字コード]]で [CN[CR]] と [CN[LF]] が存在し、同じ[[ビット組合せ]]で表されます。それらの判定の処理では[[文字コード]]の違いを意識する必要はありません。[[多バイト符号]]でも支障ありません。

[644] 
[[UTF-16]] や [[UTF-32]] のような[[符号]]では [CN[CR]] や [CN[LF]] も2バイト以上になるので、[[バイト]]レベルで判定するなら注意が必要になります。





** 統計的手法による推測

[258] 
統計的手法は、[[バイト]]や[[バイト]]の連続の出現状況と、
それらが表すであろう[[文字]]や[[文字列]]の出現頻度の統計データとを突き合わせることで[[符号]]を推定します。

[259] 
有名な[[換字暗号]]の解読法に、[[英語]]の文章で [CH[e]] 
が頻用されることを利用して暗号文を解読するものがありますが、
基本的な原理はこれと同じです。

[260] 
[[文字コードの判定]]問題は、
既知の有限少数個の[[符号]]のいずれかに回答候補が絞り込まれていますから、
任意の[[換字暗号]]解読問題より簡単です。

[261] 
しかし[[符号化]]されているのが[[英文]]とは限らず、
世界中のどの[[自然言語]]かわからないし、
混合されているかもしれないし、
[[自然言語]]の文章とも限らないという難しさがあります。

[262] 
[[ファイル名]]のように利用できる材料が少ないこともあれば、
[[ネットワーク]]から取得中のデータのように利用できる材料が徐々に増えていくこともある
(= 途中で傾向が変化するかもしれないし、全体像が見えない段階で判断を迫られることもある)、
という難しさもあります。

[478] 統計的手法には原理的な限界があります。
まず、
「対応していない言語は判定できない」という根本的問題があります。
言語の頻度モデルは既知の[[自然言語]]に基づいて構築されているため、モデルに含まれていない言語、または収集されていない[[方言]]や[[スラング]]を入力された場合、
推定器は誤った言語モデルを適用するか、雑音として扱ってしまいます。
未知語彙の多いテキスト、記述体系が非標準的な言語は、とくに誤判定が起きやすい領域です。

[477] また、既知の[[自然言語]]であっても、通常の文章から逸脱した「奇抜」
な表現は統計的特徴を乱し、精度を大きく低下させます。文学的効果を狙って異常な語彙分布にしたり、
極端に省略・連結した文体を採用したり、比喩的または視覚的な表記
(特殊記号の多用や [[AA]]、[[ギャル文字]]などの利用) を行うと、
言語モデルの前提である頻度の安定性が破壊されます。
「ハングル表記の日本語」「ヘブライ文字で書かれた英語」のような、
文字と言語の一般的な組合せと乖離しているデータも、統計的手法の想定外です。

[479] 
[[自然言語]]的でないデータの扱いはさらに困難で、例えば「文字コード表」「文字一覧表」「索引」
のような資料は、特定の語や文字が異常に均等に、あるいは偏って出現するため、
語の使用頻度に基づく判定はほぼ機能しません。


[646] 
統計的に不安定な短い入力では、長い入力と同じ判定結果が得られるとは限らないという点も重要です。これは、判定器の挙動を調整する際に「最小の再現データを用意し、その入力に対して望ましい出力が得られるように修正する」という一般的な開発手法が必ずしも通用しないことを意味しています。短い入力は統計量そのものが揺らぎやすく、小さなバイトの偏りが大きく結果を左右してしまうため、点的なテストケースを追加しても、それが広い入力空間における挙動の改善につながるとは限りません。むしろ、短い断片を対象とした局所的な調整が、長い入力に対して逆効果となることもあり得ます。こうした特性が判定器の開発の難しさの最大の要因のひとつです。



*** 言語モデル

[263] 
多くの判定器は[[自然言語]]の文章の[[文字]]や[[文字]]の連続 ([[n-gram]]) 
の出現頻度に基づき言語モデルを用意し、推定に使います。

[264] 
具体的にどのような言語モデルを作り、どのように保持し、
どのように処理に使うかは、それぞれの判定器で違います。

[475] 
同じ[[自然言語]]や同じ[[文字コード]]の言語モデルと言っていても、
その実態は実装ごとにまったく違うので、
基本的には他の実装には流用できません。

[476] 
例外的に、 [CITE[UnivCharDet]] の系譜の各種判定器は共通祖先の[[オープンソースソフトウェア]]からの派生なので、
他のソフトウェアのソースコード上のデータや言語モデル生成ツールを流用できることがあります。
その場合でも、言語モデルの使い方に手が入っている実装も多いですし、
判定器内の各構成部分のバランスの違いもありますから、
無調整で流用できるとは限らないことには注意が必要です。

**** 言語対応と言語判定

[480] 
設計によるところも大きいですが、
言語モデルは必ずしも1つの[[自然言語]]ごとに1つとする必要はなく、
[[文字]]の利用度が似た傾向にある複数の[[自然言語]]をまとめたモデルを用意することで足りる場合もあります。

[481] 
欧州など複数の[[自然言語]]で同じ[[文字コード]]体系を共有している領域では、
細かく[[自然言語]]を区別するよりもまとめた方が精度も処理速度も良くなることもあります。
[[借用語]]や[[固有名詞]]や引用文で混在しがちな[[言語]]群は、
細かく分ける方が結果が悪くなるかもしれません。

[482] 
言語モデルの種類が多いほど、必要な処理が増えるということですから、処理速度は悪化します。
しかし言語モデルを統合しすぎても、言語の特徴が均されて見えづらくなりますから、
判別精度は悪化します。
実データの傾向を見ながら適度なバランスで分割・統合された言語モデルを用意し、
それらを使って結果を導出する計算のパラメーターを調整していく地道な作業が必要となります。

-*-*-

[483]
判定器のなかには、[[文字コード判定]]と併せて[[言語判定]]の機能を備えるものも存在します。
確かに[[自然言語]]を特定して[[文字]]の頻度から[[符号]]を判定するという判定器の仕組みは、
[[自然言語]]の判定器という側面も持っています。

[484]
しかし、この二つの機能を統合することが優れた実装戦略であるかについては慎重な検討が必要です。
[[文字コード判定]]と自然言語判定では、要求される言語モデルの精度や粒度が異なるためです。
[[文字コード]]の種類よりも[[自然言語]]の種類の方がはるかに多く、
細分化された言語モデルが必要になります。また、[[UTF-8]] 
のように[[符号構造]]を利用すれば言語モデルなしで判定可能な[[符号]]であっても、
統合してしまうと結局は各[[自然言語]]ごとのデータを用意する必要が生じ、
不要な複雑さを抱え込むことになります。

[485]
とりわけ[[欧州]]の諸言語のように、使用する文字種も[[符号構造]]もよく似ている場合、
[[文字コード]] × [[自然言語]]の組合せごとに類似したモデルが多数必要となります。
最低でも十数個規模の言語モデルを管理することになります。このような環境では、
計算結果の小さな差異で優劣が入れ替わるので、調整が綱渡りのように不安定なものとなります。

[486]
さらに重要なのは、誤判定のコストの違いです。
[[自然言語]]の誤判定は大きな影響がないことが多いですが、
[[文字コード]]の誤判定はデータの読解不能 ([[文字化け]])
という致命的な結果を招きます。
綱渡りの調整で判断を迫られた場合には[[文字コードの判定]]を優先せざるを得ませんが、
[[自然言語]]の判定精度の足を引っ張るとしたら本末転倒です。

[487] 
新たな[[自然言語]]への対応を増やす際にも、対応済みの[[自然言語]]の判定への悪影響はもちろん、
対応済みの[[文字コードの判定]]への悪影響を回避する必要があり、
[[自然言語]]の追加の開発コストとリスクが大きくなってしまいます。

**** 言語モデルの開発

[488] 
言語モデルの開発は容易ではありません。
対象となる[[言語]]の文章を大量に収集し、分析しますが、
世界中の各言語の文章群 ([[コーパス]]) の入手からして困難です。

[497] 
[[平成時代]]初期に開発された 
[CITE[UnivCharDet]]
も苦労したと思われ、
言語モデルの都合で[[西欧]]と[[中欧]]への対応に制限があるなど機能性に影響が出ています。
[CITE[UnivCharDet]] 
の系譜のソフトウェアの多くはその言語モデルをそのまま引き継いでいます。

[498] 
[CITE[ced]]
は
[[Google]] のデータベースを利用しているようです。
[[Google]] が世界中から集めた [[Webページ]]の分析結果を[[自由ソフトウェア]]として利用できるのは素晴らしいことですが、
[[Google]] 社外の我々はそれをただ使うことしかできず、
研究することも改良することも、
他に流用することもほとんど不可能という限界も抱えています。


[499] 
[CITE[ced]] に限らず他の判定器の言語モデルも、
基本的には「そこにある」という以上のことはどうにもできない不透明なデータです。
微調整くらいはできるかもしれませんが、
完全に再生成するには同一の元データを用意し、
同じ方法で計算、加工しなければなりません。
完全に再生成できなければ改良もできません。
ところがすべての元データを用意するのは原作者すら不可能な場合が多いです。

;; [500] 
これは近年 [[LLM]] 等の [[AI]] 技術で問題となっている構図とよく似ています。
[SEE[ [[OSAID]] ]]


[489] 
[CITE[UnivCharDet]] の系譜のソフトウェアの一部や
[CITE[chardetng]] [SRC[>>252]]
は
[CITE[Wikipedia]]
の記事を使っています。
[CITE[Wikipedia]]
には様々な分野の記事が集まっており、
適度に[[固有名詞]]や[[外来語]]も混ざっていると考えられますから、
目的に適った文書群といえます。

[490] 
ただし [CITE[Wikipedia]] が万能ともいえません。
まず、 [CITE[Wikipedia]] に存在しないか、十分な記事がない[[自然言語]]では適しません。

;; [491] 幸い、 [[Unicode]] 以前に独自の[[文字コード]]規格を開発し流通させてきた[[自然言語]]の多くは
[CITE[Wikipedia]] が存在しているようです。しかし[[フォント依存符号化]]を使ってきた少数言語などはカバーされていないことがあります。

[492] 
また、[[ファイル名の文字コード]]の判定のような一般の文章とは異なる語彙の偏りを持つ可能性がある対象に適用する場合の
[CITE[Wikipedia]] 由来のデータの有効性は明らかではありません。

[493] 
[[音楽]]ファイルの[[メタデータ]]や [[subtitle]] も一般の文章とは異なる偏りを持つ可能性があります。
ただ [CITE[Wikipedia]] にも楽曲やアーティストの記事はありますから、
カバーされていないともいえません。
有効なのかどうか明確ではないという状況です。

[494] 
[[Web]] では[[文字コードの判定]] (推定) が必要なのは初期の [[Webページ]]が中心です。
既に二十年前後が経過しており、
[[自然言語]]の表記や[[語彙]]にも多かれ少なかれ変化が生じていると考えられます。
[[正書法改革]]が行われた[[言語]]もあります。
現在の [CITE[Wikipedia]] から作成した[[言語モデル]]が当時の [[Webページ]]に機能するかどうかは、
慎重にならざるを得ません。

[496] 
これについては、
[CITE[UnivCharDet]] の系譜や
[CITE[chardetng]]
を使った古い [[Webページ]]の判定に顕著な劣化が見られないことから、
実用上の問題にはならなそうです。

[558] 
[CITE[Wikipedia]] は[[中文]] ([[簡体字]] / [[繁体字]]),
[[セルビア語]] ([[キリル文字]] / [[ラテン文字]])
で同じ記事データを別表現に自動変換しています。
元データは中途半端な混在の可能性が、
変換済みデータは不自然な表記の可能性があり、
取り扱いには注意が必要となります。

[509] 
[CITE[Wikipedia]] は整った説明調の文章が多く、
会話文や俗語に乏しいことには特に注意が必要かもしれません。


[495] 
[[Unicode]] とそれ以外の[[文字コード]]とでは異なる符号化モデルを採用していることがあります。
特に[[アジア]]では、地域で使われてきた[[文字コード]]や[[フォント]]と [[Unicode]]
とが「文字」の概念のレベルで違っているケースが散見されます。
[CITE[Wikipedia]] など [[Unicode]] のデータはそのままでは適用可能な[[言語モデル]]にならないかもしれません。
[[Unicode]] から当該[[文字コード]]へ変換することもできるでしょうが、
変換器の出力は当時の一般的な入力方法での利用実態と乖離していることも懸念されます。

[501] 
[[Unicode]] 以前の[[文字コード]]の文書では、
当該[[文字コード]]にない[[文字]]を[[代用表記]]にしていたり、
[[文字参照]]で表したりしていることもあります。
こうした文書では通常の文章と違った文字の利用頻度となることがあります。

[502] 
どこの国でも初期の [[Webページ]]では[[英語]]が使われがちです。
[[英語]]と地元の[[固有名詞]]の組合せは、
地元の言語とも純粋な[[英語]]とも違った文字の利用頻度となることがあります。

[503] 
こうした事情を抱えた古い [[Webページ]]は、
[CITE[Wikipedia]] 由来の言語モデルをそのまま単純に使った判定では必ずしも正解を得られないようです。


[504] 
注意が必要な具体的事例:

- [505] [[ルーマニア語]]の[[文字]]の選択 [SEE[ [[ルーマニア語文字問題]] ]]
- [506] [[越南語の文字コード]]の符号化モデルの違い
([[VNI]], [[TCVN3]], [[windows-1258]]) >>613
- [508] [[半角カナ]]の符号化モデルの違い ([[濁点]]、[[半濁点]]) >>613
- [507] [[インド系文字の文字コード]]の符号化モデルの違い
- [589] [[CJK互換漢字]]に対応付けられている[[漢字]]およびそれに関係する[[CJK統合漢字]]に対応付けられている[[漢字]]の扱い


**** 記号の扱い


[608] 
言語モデルにおいて狭義の文字 ([[letter]]) 以外の[[数字]], [[句読点]], その他の[[記号]]等をどう扱うのが良いのか、は難問です。一般の [[n-gram]] 等でもそれらは除去したり、 [CN[SP]] に置換したりすることが多いです。 [[記号]]等は任意の単語の前後に現れたり、同じ位置でも時と場合によって違う記号を使い分けたり、[[自然言語]]とは異なる用法の列を形成したりするので、[[自然言語]]の[[単語]]における [[letter]] の出現パターンとは違うことが多く、混ぜたモデルが有効に機能するとは限らないのです。

[609] 
[[記号]]を混ぜた言語モデルは利用[[コーパス]]の性質の影響も強く受けてしまうと考えられます。 [CITE[Wikipedia]] 由来のモデルだと、整った説明文に出てくる[[句読点]]は頻出するでしょうが、装飾的な記号の使われ方はあまりしないと予想されます。[[俗語]]や[[文学]]的文章、専門性の強い技術的文章などの[[記号]]の使われ方に適応できるかどうかが未知数です。

[610] 
[[記号]]等がまったく判定に寄与できないわけではなく、言語モデル以外の方法で、あるいは [[letter]] 用とは別の言語モデルで加味することはあり得ます。例えば「、」や「。」に相当するバイトが定期的に頻出するなら日本語文字コードの可能性が高いとして加算する (ただし皆無だとしても減点要素にはしない) という採点は可能でしょう。[[欧文]]で[[語頭]]や[[語末]]にある[[バイト]]は引用符かもしれない、などといった性質もうまく盛り込める形のモデルも有用そうです。

[611] 
[CITE[UnivCharDet]] の系譜の判定器の言語モデルは基本的には [[letter]] の出現頻度等で構成されています。系譜の実装の一部は記号類の出現の度合いを判定に加味することがあります。

[612] 
[CITE[chardetng]] は記号等をいくつかの種別に分けて [[letter]] とは違った方法で判定に加味しています。

**** 結合文字の扱い

[613] 
[[結合文字]]を扱う必要がある場合、

- [614] 言語モデルにおいて[[結合文字]]はどう扱うべきなのか
- [615] [[合成済み文字]]を使う[[文字コード]]と[[基底文字]]と[[結合文字]]の組み合わせを使う[[文字コード]]があるとき、一方のデータによる言語モデルを他方の判定にも適用できるのか

といった疑問が生じます。これが主に問題となるのは[[越南語の文字コード]]の各種です (>>561)。また、技術的には[[結合文字]]ではありませんが、[[半角カナ]]の[[濁点]]・[[半濁点]]にも同じことがいえます (>>571)。

[616] 
[[合成済み文字]]かどうかによって[[基底文字]]の出現頻度は変化しますし、[[基底文字]] + [[結合文字]]や[[結合文字]] + 次の[[文字]]の [[bigram]] が変化します。この違いがどう影響するのかです。

[617] 
1つ目の疑問 (>>614) については、基本的には [[letter]] と同じ扱いで良いと思われます。

[618] 
少し意外に思われますが、 [[越南語の文字コード]]とそれ以外の欧州などの[[文字コード]]の区別に[[結合文字]]の扱いはあまり寄与しません。 [CITE[UnivCharDet]] の系譜の判定器で [CITE[Wikipedia]] から生成した言語モデル、すなわち[[合成済み文字]]方式の文字が含まれる可能性が高いモデルを使ったものがありますが、[[越南語]]かどうかを概ね正しく判定します。また、 [CITE[chardetng]] は独自の方法で決めた2種類の表現でデータを作っていますが、どちらでも大差はないという報告になっています [SRC[>>252]]。

[619] 
このような結果になるのは、それ以外の文字や並びによる[[越南語]]かどうかの区別が大きな要素であって、[[非ASCII文字]]部分で[[越南語の文字コード]]のどれを使っているかによる差が小さいということです。[[越南語の文字コード]]相互の差が付きにくいという問題は[[合成済み文字]]か[[基底文字]]と[[結合文字]]の組み合わせかを区別して適切な言語モデルを使えば少し改善できますが、それだけでは不十分です。[[越南語]]の語の構造を意識して採点すると更に改善できます (>>561)。あるいは [[trigram]] などでも改善できるかもしれません。

[620] 
この[[越南語]]の結果が他の言語の同様の符号化モデルの違いにも当てはまるのかどうかは定かではありません。[[越南語]]は規則的な単語の構造で[[結合文字]]の出現の仕方も特異なので、むしろ例外的なのかもしれません。

[621] 
[[基底文字]]と[[結合文字]]の組み合わせが一般的なものと異なる場合は、積極的に減点した方が良いかもしれません。[[越南語]]の場合はそれを語全体の構造を意識した採点により実現できますが、他の言語では前後2字の連続によって減点することになるでしょうか。



*** ASCII文字の扱い

[305] 
[[EBCDIC]] などを除くと、ほとんどの[[文字コード]]体系は [[ASCII文字]]を共通に持っています。
そのため
[[ASCII文字]]は[[文字コードの判定]]に大きくは寄与しません。

[306] 
また多くの[[マーク付け言語]]や[[プログラミング言語]]は[[英語]]の[[語彙]]を大量に含んでいます。

[307] 
[[HTML文書]]の場合[[要素名]]、[[属性名]]、 [[JavaScript]] コード、
[[CSSスタイルシート]]などの形で多くの[[英語]]の [[ASCII文字]]表記を含みます。
更にいえば、初期の [[Webサイト]]はどの地域でも[[英語]]が多いです。
本文が[[英語]]でないとしても、話題が[[インターネット]]や[[計算機]]の技術系のページでは[[英語]]や[[英語]]由来の
[[ASCII文字]]の語が極めて頻出します。

[315] 
判定に使う文字の出現頻度の情報は、想定される[[自然言語]]の文章から計算されています。
[[英語]]の濃度が極度に大きいと、本来の[[自然言語]]の出現頻度から離れていき、
判定が狂う要因となってしまいます。


[308] 
こうした事情があるので入力の [[ASCII文字]]をどう取り扱うかは設計上無視できない問題となります。

[309] 
[[ASCII文字]]を無視すれば、こうした「ノイズ」も一気に除去することができ、
[[非ASCII文字]]の[[文字コードの判定]]に注力し、関係ない部分の処理の負担を軽減できます。

[310] 
一方で欧州言語など[[ASCII文字]]が[[言語]]の表記の主体となる場合、
[[非ASCII文字]]の割合が少ないので、
すべての[[ASCII文字]]を捨ててしまうと[[言語判定]]の重要な情報まで捨ててしまうことになります。

[311] 
中間解として、 [[非ASCII文字]]の周囲の [[ASCII文字]]を判定に活用するのが現実的です。
[[ASCII文字]]と[[非ASCII文字]]にまたがる [[n-gram]] の出現頻度は、
とりわけ欧州言語の判定に重要です。

[312] 
[CITE[UnivCharDet]] は[[非ASCII文字]]を含む単語を[[8ビット符号]]の判定に利用しています。

[313] 
[CITE[chardetng]] はそれより攻めていて [[ASCII文字]]同士の[[連接]]は判定に使わないようです。

[314] ただしこうした戦略の違いがどれだけ判定性能や動作速度や消費メモリー量に影響を及ぼすのか、
定量的な比較はあまり行われていないようで不明瞭です。

[316] 
欧州語で、しかも[[ファイル名]]のような短い文字列が入力のとき、
[[ASCII文字]]だけの部分でも[[言語判定]]のヒントに使えれば、
数少ない[[非ASCII文字]]やその前後だけでは情報が不足する[[言語判定]]の補強材料になります。
しかし両者が関係ない単語の場合もあって、そのときは誤判定のリスクが増大します。



*** エスケープとの混合

[188] 
[[エスケープ]] ([[HTML]] の[[文字参照]]など) とそうでない通常の[[文字]]が混合されている場合、
純粋な[[文字列]]とは違った[[文字]]分布になってしまう場合があります。

[189] 
単純に [[ASCII文字]]だから、[[マーク付け言語]]の構文要素だから、
といった理由で[[エスケープ]]を除去すると、通常の[[文字]]の前後関係が[[言語]]の一般的なパターンと外れてしまい、
判定に失敗することがあります。

[196] 
[[エスケープ]]とそうでない[[文字]]が混在するのは、特に理由が無いこともありますが、
敢えて混在させていることもあります。[[文字化け]]しやすいとか、
その[[文字コード]]に存在しないとかです。得てしてそれらは[[文字コードの判定]]の際どい条件に関わってくる要素になりがちです。





*** 欧州ラテン文字系文字コードの区別

[200] 
[[Windows-1252]] (含 [[ISO-8859-1]]) と [[ISO-8859-2]] と [[Windows-1250]]
は区別の難易度が高いことが知られています。

[201] 
そもそも[[ラテン文字]]系[[言語]]は文章の多くが [[ASCII文字]]で、
[[言語]]次第で少々の[[非ASCII文字]]が混ざるという構造です。
[[非ASCII文字]]主体の他[[文字]]の[[言語]]よりも判別が難しいです。

[202] 
[[Windows-1252]] と [[Windows-1250]] は似た構造ですが、
収録される[[文字]]の種類は一部で著しく異なっています。
文章に少々混じる[[非ASCII文字]]のうちの更に一部の頻出文字が共通で、
残りが全く異なるので、[[バイト]]の並びとして見たとき、
どちらかにわかに判断しがたいことが多いです。

[203] 
[[Windows-1250]] と [[ISO-8859-2]] はだいたい同じで少し違います。
どちらも[[中欧]]でよく使われていた[[文字コード]]で、
同じような[[言語]]で同じように使われていて、
わずかな違いがどちらなのか判定するのが難しいです。


[211] 
[[Mozilla]] の [CITE[UnivCharDet]] は [[ISO-8859-2]] に対応しているものの、
[[ISO-8859-1]] が誤判定されてしまうとして無効化されています。
[CITE[UnivCharDet]] の派生の中にはこれを改善して有効化しているものもありますが、
それらも完璧に判定できるわけではありません。


[212] 
[CITE[ced]] は [CODE[.hu]] [[ドメイン]]のみ [[trigram]] を有効にするなど、
特別な処理で判定を強化しています。それでも [CITE[Chrome]]
はたまに判定を誤ります。
[SEE[ [[ロケール等による文字コード判定の補助]] ]]

[213] 
[CITE[chardetng]] も [[TLD]] による傾斜など特別な処理で判定を強化しています。
それでも [CITE[Firefox]] はしばしば判定を誤ります。
[SEE[ [[ロケール等による文字コード判定の補助]] ]]

[214] 
完璧な判定は困難ですから、どの手法を採るにせよ、最終的に[[文字コード指定メニュー]]など[[利用者]]が選択を覆せる手段が必須です。

[EG[

[281] >>280 は[[ハンガリー語]]で書かれた [[HTML]] です。
各種の判定器は [[ISO-8859-2]], [[windows-1250]], [[windows-1252]]
と判断が分かれています。
[CITE[Firefox]] は [[windows-1252]] と考えます。
[CITE[Chrome]] は [[windows-1252]] と考えますが、
[CITE[ced]] にバイト列を与えると [[windows-1250]] と回答します。
[TIME[2025-11-24T06:15:55.100Z]]

[282] 実際には3符号化の共通文字が[[非ASCII文字]]でも多いのですが、
[[ハンガリー語]]であることと[[ハンガリー語]]の[[文字]]の使い方から
[[ISO-8859-2]] / [[windows-1250]] と考えるのが妥当です。
>>280 の範囲では [[ISO-8859-2]] と [[windows-1250]] は同等です。

;; [283] [CITE[Firefox]] と [CITE[Chrome]] は[[文字コード指定メニュー]]がないので、
[[文字化け]]したまま修復できません。一種の不具合といえます。

[REFS[

- [280] 
[CITE[Bemutatkozik a WILD WEST GYÕR]], [TIME[2025-11-24T06:08:55.000Z]] <https://www.members.tripod.com/wildwestgyor/bemut.htm>

]REFS]

]EG]

-*-*-

[539] 
[[ラテン文字]]は[[言語]]が多いので、
言語モデルは個々の[[言語]]ではなくいくつかまとめた[[言語]]群ごとに用意するのが無難です
(>>485)。

[540] 
[[西欧]] ([[windows-1252]] / [CODE[iso-8859-1]] / [[macintosh]] / [[ibm850]] の類)
のうち、[[言語]]
[CODE[fo]], [CODE[is]]
は利用文字が他と大きく違います。
[CITE[chardetng]] は[[西欧]]をこれらとそれ以外とで二分しています
[SRC[>>252]]。
定量的評価がなされているのかは不明ですが、
有効な戦略のようにみえます。

[541] 
残りの[[西欧]] (旧[[植民地]]等を含む。) は、
[[スカンジナビア]]・[[ドイツ]]とそれ以外とでやや利用文字に異なりがあるので、
二分するのが一案と思われます。

[542] 
したがって[[西欧]]系の言語モデルは次の3種類にまとめられます。

- [543] [[西欧]] : [CODE[af]], [CODE[es]], [CODE[fr]], [CODE[it]], [CODE[pt]]
-- [544] 含、初期 [[Web]] ページで [[windows-1252]] + [[文字参照]]がよく使われた :
[CODE[et]], [CODE[mt]], [CODE[ro]], [CODE[rs]], [CODE[sq]], [CODE[tk]]
- [545] 南[[北欧]] : [CODE[da]], [CODE[de]], [CODE[fi]], [CODE[no]], [CODE[sv]]
- [546] 北[[北欧]] : [CODE[fo]], [CODE[is]]

[547] 
[[トルコ語]]は[[西欧]]の[[文字コード]]とよく似たものが使われますが、
微妙に違いがあり区別しづらいこと、[[大文字と小文字]]の扱いが違うこと (>>520) に注意が必要です。

[548] 
[[中欧]]、[[バルト]]はそれぞれの[[文字コード]]群に対応する言語群でモデルをまとめてしまって構わなそうです。
[[ISO-8859-3]] は専ら[[エスペラント語]]で使われたので、
これは独立させた方が良さそうです。

- [549] [[トルコ語]] : [CODE[az]], [CODE[tr]]
- [550] [[中欧]] : [CODE[cs]], [CODE[hr]], [CODE[hu]], [CODE[pl]], [CODE[ro]] (ただし >>505),
[CODE[sk]], [CODE[sl]], [CODE[tk]]
- [551] [[バルト]] : [CODE[et]], [CODE[lv]], [CODE[lt]]
- [554] [[エスペラント]] : [CODE[eo]]

[552] [CODE[et]] は >>551 と >>554 に重出しますが、この是非については検討の余地があります。

[555] 他に [[ibm865]] や [[ISO-8859-15]], [[ISO-8859-16]] 
などを扱うなら、対象言語に特化した言語群のモデルを用意したほうが良いかもしれませんが、
>>543 との関係を検討しなければなりません。

[556] なお各[[言語]]と[[国家]]と[[文字コード]]の利用実態については[[ロケール等による文字コード判定の補助]]も参照。

[553] [[越南語]]は[[言語]]も[[文字コード]]も性質が大きく異なるので、別途の扱いが必要です。



*** 東側諸国の言語モデル

[525] 
[[旧ソ連]]を中心とする[[東側諸国]]は[[20世紀]]末に[[正書法]]改革や[[ロシア語]]からの脱却を進めたところが多く、
その影響が問題となります。

[526] 
初期の [[Webページ]]の[[文字コード]]を扱うという目的で [[Internet Archive]] に残る各国の古い
[[Webサイト]]を調査すると、地域によって差も大きいものの、

- [527] [[ロシア語]] ([[windows-1251]], [[KOI8-R]])
- [528] [[英語]]
- [529] 現地言語の[[ラテン文字]]表記 ([[windows-1250]], [[windows-1252]], [[windows-1251]],
[[KOI8-R]] のいずれかと、それらで足りなければ[[文字参照]])

が大部分で、国単位の例外で

- [530] [[アルメニア文字]]
- [532] [[ジョージア文字]]
- [531] [[ブルガリア語]]の[[キリル文字]]表記 ([[windows-1251]])
- [533] [[セルビア語]]等の[[キリル文字]]表記 ([[windows-1251]])
- [534] [[マケドニア語]]の[[キリル文字]]表記 ([[windows-1251]])
- [535] [[蒙古語]]の[[キリル文字]]表記 ([[MNS 4330]])

があります。[[ラテン文字]]に移行した国の旧[[キリル文字]]表記や[[ロシア連邦]]の少数言語の[[キリル文字]]表記は見つけるのが困難です。
[SEE[ [[ロケール等による文字コード判定の補助]] ]]

[536] 
従って言語モデルの開発において旧[[正書法]]のデータを入手する必要性は大きくなさそうです。

[538] 
現地言語の[[ラテン文字]]表記について、何度か[[正書法]]の改定が行われている場合もありますが、
少なくても[[文字コードの判定]]に関係しては、特に目立った違いのようなものは検出できません。


[537] 
[CITE[UnivCharDet]] は[[キリル文字]]に関して[[ロシア語]]の言語モデルを用意していました。
[CITE[UnivCharDet]] の系譜の判定器の中にはこれだけでは不足として[[ブルガリア語]]の言語モデルを追加したものがあります。
[[Webページ]]の判定ではこの2つのモデルがあれば他の[[キリル文字]]言語も含めて実用的な精度が得られるようです。



[HISTORY[

[523] 
[CITE[chardetng]] は[[アゼルバイジャン語]]について

>
-    For Azerbaijani, I replaced ə with ä to synthetize the windows-1254-compatible 1991 orthography.

なる調整をしたと説明しています。 [SRC[>>252]]
しかしその必要性について十分な根拠を示していません。

[524] 
[[アゼルバイジャン]]における [[windows-1254]] の利用は皆無ではないにせよ一般的とは言い難く、
ここで説明されているような表記法の利用実態があるのか、
それが判定精度に寄与するのか、といった点に不安が多いです。
実際に
[[Internet Archive]]
で確認できる古い
[CODE[.az]]
の
[[Webサイト]]は[[英語]]か[[ロシア語]]か、
そうでなければ
[[windows-1251]] と[[文字参照]]の組合せであり、
>>523 のような事例は未発見です。
[SEE[ [[ラテン文字の文字コード]], [[ロケール等による文字コード判定の補助]] ]]

]HISTORY]

[HISTORY[

[522] 
[CITE[chardetng]] は[[蒙古語]]でも調整したと説明しています。
[SRC[>>252]]
これは [CITE[Encoding Standard]] や [CITE[Firefox]] が
[[MNS 4330]] の存在を認めていないために必要になる処置です。

]HISTORY]





*** 大文字と小文字

[294] 
出現頻度による手法の多くは[[大文字と小文字]]を同一視して[[文字]]や [[n-gram]]
の頻度を見ています。ほとんどはこの手法でうまく判定できます。

[520] 
[[トルコ語]]では他の言語と [CH[I]] / [CH[i]] の[[大文字と小文字]]の扱いが違うので、
注意が必要です。

[521] 
[[日本語]]の[[平仮名]]と[[片仮名]]は使われ方が[[アルファベット]]の[[大文字と小文字]]とは違うので、
同じような取り扱いにするかどうかは悩みどころです。

-*-*-

[292] 
[CITE[chardetng]] は[[大文字と小文字]]の使い分けが自然なものを加点し不自然なものを減点しています。
[SRC[>>291]]

[293] 
[[ギリシャ文字]]ですべて[[大文字]]にした語は、[[キリル文字]]をすべて[[小文字]]にした
[[KOI-8]] や[[ヘブライ文字]]と混同しやすいとされ、
[CITE[ced]] や [CITE[chardetng]] が特殊処理を入れています。
[SRC[>>291, >>284]]


[REFS[

- [291] 
[CITE@en[chardetng/src/lib.rs at main · hsivonen/chardetng · GitHub]], [TIME[2025-11-24T08:24:04.000Z]] <https://github.com/hsivonen/chardetng/blob/main/src/lib.rs#L154>


[FIG(quote)[
[FIGCAPTION[
[284] [CITE@en[[[compact_enc_det]]/compact_enc_det/compact_enc_det.cc at master · google/compact_enc_det · GitHub]], [TIME[2025-11-24T07:39:23.000Z]] <https://github.com/google/compact_enc_det/blob/master/compact_enc_det/compact_enc_det.cc#L1770>
]FIGCAPTION]

>        // Greek all-caps is confusable with KOI8x all-lower and Hebrew.
]FIG]

- [299] 
[CITE@en[Countermeasures for various misdetections. · hsivonen/[[chardetng]]@0973b4b · GitHub]], [TIME[2025-11-24T08:50:10.000Z]] <https://github.com/hsivonen/chardetng/commit/0973b4b67da81b9be2f643d0da70536d616aec06>


]REFS]

*** ASCII 文字と非 ASCII 文字の隣接

[300] 
[CITE[chardetng]] は[[ラテン文字]]とそれ以外 ([[ASCII文字]]とそれ以外) 
の隣接で非[[ラテン文字]]系[[符号]]を減点しています。
[SRC[>>299, >>252]]

[518] 
[[日本]]でよく見る、[[ラテン文字]]の並びの途中にぽつんと[[漢字]]が1字混ざるタイプの[[文字化け]]の抑制になりそうです。

[519] 
この種の規則を組み込むには慎重な評価が必須です。
[[多バイト符号]]の第2バイトが [[ASCII英数字]]になることはよくありますし、
[[日本語]]などで[[漢字]]と[[ラテン文字]]が隣接することは割とよくあります。


*** 語長

[297] 
[CITE[chardetng]] は[[語長]]が23[[超]]なら[[タイ文字]]以外を減点しています。
[SRC[>>296]]

[298] [CITE[chardetng]] は [[EUC-KR]] の[[ハングル]]の[[語長]]が5[[超]]なら減点
([CODE[EUC_KR_LONG_WORD_PENALTY]]) しています。 [SRC[>>296]]

[301] 
他の実装にはあまり見られないので有効性は不明瞭です。

[302] 
[[johab]] は他の符号と誤認の排除に[[ハングル]]の[[語長]]の平均 (大雑把に [N[3]]
字くらい) との乖離の検知が有効なようです。


[REFS[

- [296] 
[CITE@en[[[chardetng]]/src/lib.rs at main · hsivonen/chardetng · GitHub]], [TIME[2025-11-24T08:46:35.000Z]] <https://github.com/hsivonen/chardetng/blob/main/src/lib.rs#L755>

]REFS]


*** 書字方向

[303] 
[[ISO-8859-8]] など[[視覚順]]と[[論理順]]の区別が必要となる場合があります。

[304] 
[[ヘブライ文字]]は[[語末形]]と[[語中形]]が異なるものが5字10種あります。
[[ISO/IEC 8859-8]] や [[Windows-1255]] はそれらに別の[[ビット組合せ]]を充てています。
[CITE[UnivCharDet]] は[[ヘブライ文字]]列の先頭や末尾の[[字形]]の個数や前後から見た [[bigram]]
の評価によってどちらか判定しています。

[253] 
[CITE[chardetng]] は[[ヘブライ文字]]ではなくそれと併用される [[ASCII]] [[句読点]]の使われ方で判定しているようです。
[SRC[>>252]]


[557] 
どちらの手法も長短ありそうです。[[句読点]]法は、
題名や[[ファイル名]]や短文などで機能しない虞があります。




[REFS[

- [252] 
[CITE@en[[[chardetng]]: A More Compact Character Encoding Detector for the Legacy Web]], [[Henri Sivonen]], [TIME[2020-06-08T16:23:51.000Z]], [TIME[2025-12-03T05:01:28.298Z]] <https://hsivonen.fi/chardetng/>

]REFS]

*** 越南語

[561] 
[[ベトナム語]]は[[ラテン文字]]ですが、[[発音区別符]]を多用します。
[[Unicode]] 以前は数個の異なる[[文字コード]]が使われていました。
[SEE[ [[越南語の文字コード]] ]]

[562] 
いずれも [[ASCII]] の拡張ですが、
[[欧米]]の[[ラテン文字の文字コード]]とは言語の構造も[[文字コード]]の構造も違います。
ところが[[ASCII英数字]]に[[非ASCII文字]]が少々混じるという基本構図は同じなので、
単純な [[bigram]] の出現頻度だと区別が付き辛いこともあります。

[563] 
[[越南語]]は[[音節]]ごとに[[分かち書き]]され、
[[借用語]]や[[略語]]などを除くと、
3, 4つ前後の[[子音]]字と[[母音]]字が非常に規則的に並びます。
[[非ASCII文字]]も[[母音]]字等に規則的に出現します。

[564] 
この性質を使うと[[越南語]]主体の文章とそれ以外は高確度で区別できます。

[565] 
ただし[[英語]]に少々[[越南語]]が混じる文章を扱うと難しく、
[[非ASCII文字]]が少なめの[[欧文]]との区別が付きにくいことには変わりありません。

[566] 
[[越南語の文字コード]]の各種の中には、すべての[[文字]]が[[合成済み文字]]であるもの
[WEAK[(現在の [[Unicode]] の一般的な利用法はこちら。)]]
と、
[[結合文字]]を使うものがあります。[[大文字と小文字]]がすべて揃っていないものもあります。

[567] 
[[結合文字]]の有無などで[[文字]]の単位が異なり、
出現頻度や隣接の仕方が違いますから、
言語モデルはそれぞれの[[文字コード]]の利用実態に合わせて開発する必要があります。

[568] 
[CITE[chardetng]] は [[Unicode]] と符号化モデルが異なる
[[windows-1258]] 
用のデータを [CITE[Wikipedia]] の [[Unicode]] 用データから生成するためあれこれ操作しているようです。
[SRC[>>252]]
しかし、少なくても [[Web]] において [[windows-1258]] が大規模に利用された形跡がなく、
当該操作で製作されたデータの有用性は不明瞭です。
[SEE[ [[windows-1258]] ]]

[569] 
[[Internet Archive]] に残る初期の [[Web]] で実際に[[越南語の文字コード]]を利用した
[[HTML文書]]での実験によると、[[越南語]]版 [CITE[Wikipedia]] の [[Unicode]]
記事から作った言語モデルで
[[viscii]], [[x-viet-vps]], [[x-viet-tcvn3]], [[x-viet-vni]]
(とその他欧米の[[文字コード]]) の区別は不可能ではないものの、
不安を感じる精度であります。 [[viscii]], [[x-viet-vps]] は[[合成済み文字]]なのでこのままでよく、
[[x-viet-tcvn3]], [[x-viet-vni]] は当時の当該[[文字コード]]の文書群を集めて製作した言語モデルに切り替えることで、
一応実用に耐える精度は実現できるようです。

[570] 
ただ、[[越南語]]が少ない場合 (>>565) などに改良の余地はあります。
どこまでを言語モデルの改良により、どこからを他の手法の組み合わせによるべきかも探求の余地があることでしょう。






*** 半角カナ


[571] 
[[半角カナ]]は、[[日本語情報処理]]における歴史的功績は大きく、幾度も流行のように使われてきた一方で、[[文字化け]]の元凶として嫌われてきました。
[SEE[ [[半角カナ]] ]]
[[半角カナ]]が嫌われる技術的原因の多くが[[文字コードの判定]]に関係します。すなわち、

- [572] 
[[EUC-JP]] を [[Shift_JIS]] と誤読すると[[半角カナ]]が頻出します。つまり[[文字化け]]すると[[半角カナ]]が現れます。
- [573] 
[[Shift_JIS]] の[[半角カナ]]は [[EUC-JP]] の2バイト文字と[[バイト列]]として区別がつかないことが多いです。つまり[[半角カナ]]を使うと[[文字化け]]しがちです。
- [574] 
[[ISO-2022-JP]] の正式仕様に[[半角カナ]]はありません。そのため[[半角カナ]]が使えなかったり、非標準の方法で出力されたりします。つまり[[半角カナ]]を使うとエラーか規格違反になり、[[文字化け]]しがちです。
- [575] 
[[Latin1]] の記号を [[Shift_JIS]] と誤読すると[[半角カナ]]になります。つまり[[文字化け]]すると[[半角カナ]]が現れます。

[576] 
[[半角カナ]]は使うべきでないと言われ続け、[[文字コードの判定]]の技術開発・実装でも[[半角カナ]]の判定はあまり重視されてきませんでした。厄介な存在にも関わらず、[[文字コードの判定]]でどう扱うのがいいのか、ノウハウはさほど蓄積されてきていません。それでいながら[[半角カナ]]が使われ続け、[[文字化け]]の元凶でもあり続けるという悪循環がありました。

[577] 
[CITE[UnivCharDet]] の系譜の判定器は入力に[[日本語]]の[[言語]]指定がなければ[[半角カナ]]だけの文字列を理解できず、欧米等の[[8ビット符号]]と誤認することがあります。 [CITE[UnivCharDet]] は[[半角カナ]]を判定に使わないので、2バイト文字がなければ他の[[符号]]に負けます。

[578] 
[CITE[chardetng]] は[[半角カナ]]と欧米等の[[8ビット符号]]の区別のための得点調整を入れており、[[半角カナ]]だけの文字列のテストを用意していますから、この問題を認識し対策していることがわかります。実際に [CITE[UnivCharDet]] の系譜の判定器よりこの種の判定は高精度です。

[579] 
[[Shift_JIS]] の[[半角カナ]]の[[バイト]]は [[Latin1]] の記号等の[[バイト]]と重なっています。 [[Web]] では [CH[©]] などの [[Latin1]] 文字が頻出します (>>265)。 [[Latin1]] 側で特徴的なパターンに加点するだけでなく、 [[Shift_JIS]] 側で不自然なパターンに減点する対策が有効です。 [[Latin1]] の記号が配置されている [N[0xA[VAR[x]]]] の領域には [[Shift_JIS]] で[[句読点]]や[[小書き仮名]]が配置されています。これらのいくつかは、他の[[半角カナ]]の後に来る可能性が高いなど、使われ方に傾向があります。そこからの逸脱は、 [[AA]] などで出現し得ることには配慮しつつも、減点要素にできます。


[581] 
[[半角カナ]]が含まれていても、[[平仮名]]や[[漢字]]も一般的な[[日本語]]の表記方法で含んでいる短くない文章なら、[[文字コードの判定]]に失敗することは多くありません。問題となるのは[[半角カナ]]のみで構成される語句です。

[582] 
いくつかある入力欄の1つだったり、多数あるファイルの[[ファイル名]]だったりで他に同じ[[文字コード]]で記述されているはずの[[バイト列]]があるなら、なるべくそれらをひとまとめにして[[文字コードの判定]]の処理を適用することで誤判定の可能性を下げられます。

[583] 
それでも[[ファイル名]]の短い文字列などで[[半角カナ]]のみで構成される[[バイト列]]を判定するべき場面はあります。[[8ビット符号]]と同じように[[半角カナ]]の言語モデルを使って出現頻度で検査するのが良いのでしょうが、考えるべきことがいくつかあります。

- [584] 言語モデルはどう作るのがいいでしょうか。
-- [585] [[半角カナ]]がどう使われるか考えてみると、大別して、 (1) 通常の日本語表記のうち片仮名部分 (2) [[人名]]の[[振り仮名]]など発音表記 (3) [[箇条書き]]などの記号 (4) 通常の日本語の文や語句だが片仮名表記、 (5) [[AA]] 等の構成要素、 (6) [[俗語]]あたりが考えられそうです。 [SEE[ [[半角カナ]] ]] このうち (3) (5) は言語モデル法で扱うのは無理です。 (1) は [CITE[Wikipedia]] などから[[片仮名]]部分を抜き出せば作れそうです。 (2) (4) が (1) と同じ言語モデルで対応可能なのかどうかは自明ではありません。 (2) (4) (6) は[[仮名漢字変換]]の[[辞書]]などを活用することも考えられますが、意味のある出現頻度データが得られるのか不安があります。
-- [586] (1) - (6) の用途の言語モデルは、合わせて1つ作るのが良いのでしょうか、それともいくつか作るのが良いのでしょうか。合わせることはできるのでしょうか。
- [587] [[半角カナ]]には[[濁点]]・[[半濁点]]付き[[仮名]]がありません。濁点・半濁点を親文字から分離して頻度や隣接を数える必要があります。
- [588] [[半角カナ]]の言語モデルと [[Shift_JIS]] の判定はどう組み合わせるのが良いのでしょう。[[半角カナ]]のみと [[Shift_JIS]] 全体とを別の[[符号]]であるかのように扱うのが良いのか、 [[Shift_JIS]] の判定の一部として[[半角カナ]]も組み込むのが良いのか、どちらの設計も長短ありそうです。


*** インド系文字

[622] 
[[インド系文字の文字コード]]は数多ありますが、それらの区別の技法の研究や実装の事例はそれほど多くないようです。多くの[[文字コード]]が[[フォント依存符号化]]であり、 [[HTML]] や[[ワープロ]]の[[文書形式]]における[[フォント]]指定の方法で[[フォント名]]が明示されているので、それを読み取ることで処理は足り、バイト列からの推定などの高度な手法の出番は多くありません。

[623] 
しかし[[平文]]や[[フォント]]指定なしでの利用の実績がある[[文字コード]]体系もあり、それらはバイト列からの推定が必要になります。

[624] 
[[インド系文字の文字コード]]のほとんどは [[Unicode]] とは異なる符号化モデルを採用しています。主要な[[文字コード]]は [[Unicode]] との変換器がありますから、 [[Unicode]] のコーパスから変換したデータを作ることは一応可能ですが、変換器の生成データが従来[[文字コード]]の実用当時の使われ方と同じかどうかは不安があります。変換器は生成しないけれども実用されたバイトの並びが存在するかもしれませんし、バイトの並び方に実用とは異なる偏りが生じる可能性もあります。

[628] 
したがって、[[インド系文字の文字コード]]の言語モデルを作る際には、 [[Unicode]] のコーパスを使うのではなく、当該[[文字コード]]が実用されているデータを収集するの必要があります。
十分な分量を集めることが難しい可能性もありますが、 [[TSCII]] や [[TAB]] のような主要な[[文字コード]]体系については世界の他の[[文字コード]]も含めて互いに区別するのに十分な精度が出せるモデルを生成できることが確認されています。

[625] 
[[チベット文字の文字コード]]については、[[チベット文字]]で頻出する[[文字]]の[[バイト]]の出現頻度を使った研究があり、[[中華人民共和国]]の[[多バイト符号]]系の[[文字コード]]体系も含めて検討されています。 [SEE[ [[チベット文字の文字コード]] ]]

[626] 
[[チベット文字の文字コード]]の変換器で、入力に含まれる [[ASCII文字]]の並びが[[英語]]なのか、[[チベット文字]]の[[翻字]]なのかを語の構造や割合によって推測して決定するものがあります。 [SEE[ [[チベット文字の文字コード]] ]]

[627] 
[[ビルマ文字の文字コード]]の判定器は入力に含まれる[[Unicode文字]]の並びのパターンを検査して[[フォント依存符号化]]
(主に [[Zawgyi]])
を判定するものが多いです。
入力が [[UTF-8]] [[文字列]]となるのが独特な点です。
[SEE[ [[ビルマ文字の文字コード]] ]]

[629] 
[[Zawgyi]] も[[フォント依存符号化]]として使われることが多いので[[フォント名]]で判定できそうなものですが、判定器の実装の多さを見るにそれ以外の需要もかなりある (あった) ようです。 [[SNS]] の本文や[[動画サイト]]の説明文などにも[[平成時代]]末頃までは [[Zawgyi]] が散見され、[[フォント名]]情報がないので判定が必要になります。

-*-*-

[630] 
他にない珍しい取り組みとして、[[フォント]]データを調べて[[文字コード]]を識別する研究の事例があります。 [SEE[ [[クメール文字の文字コード]] ]] [[バイト列]]の[[文字コードの判定]]とは違って[[符号構造]]くらいしか使える要素がなく、出現頻度による判定は適用できません。もしかすると[[グリフ]]データの類似度を利用するような手法への発展の可能性もあるかもしれません。

[631] 
[[Unicode]] 以外がほとんど使われなくなった現在では実需要もほとんどないとは思われますが、過去のデータやフォントの調査と分析でこうした手法が役に立つ場面もあるかもしれません。[[インド系文字の文字コード]]の全体像は未だ解明されておらず、有名な[[フォント]]とその符号体系は知られているものの、有名なもの以外の[[フォント]]や各[[符号]]の類縁関係など今後の調査研究が期待される領域は多く、人間の作業を補助する機械的手段は有効と思われます。






** 発展的手法

[632] 
それほど実践例の報告はありませんが、近年の[[機械学習]]技術の進展は、[[文字コードの判定]]の技法にも一定の発展可能性を与えています。この分野は従来の判定器の比較的単純な統計モデルで十分に高い精度が得られるため、大規模な再発明が行われることはありませんでした。しかしその反面、短い入力、利用事例が少なく情報が少ない[[文字コード]]体系、[[文字コードの混在]]、[[文字コードの修復]]が破損データなど依然として適用が難しい領域も残っています。

[633] 
[[深層学習]]、とりわけ[[バイト列]]を直接扱える [[Transformer]] 系モデルは、この“情報が薄い状況”にも比較的強く、十分な[[訓練データ]]さえ確保できれば、短い[[バイト列]]から符号化の特徴的な癖を直接学習し、既存手法を上回る判断を行える可能性があります。さらに、複数候補の[[符号化]]を自然に同時出力し、曖昧性の分布を確率的に提示できるという点は、既存の判定器の「確信度」が実装依存である問題に対しても、一つの解決方向を示し得ると思われます。しかし現実には、流通する実データが少なく、かつ[[文字化け]]を含む多様な“現実的な失敗例”を網羅した訓練データが存在しないため、モデル構築に必要なコストは決して小さくありません。[[GPU]] 計算資源を用いた大規模学習を必要とするほどの商業的需要がこの分野にあるかといえば否定的で、歴史やアーカイブの研究者の関心も高くないのが現状です。

[634] 
より[[生成的なモデル][生成モデル]]を利用すれば、従来の「正しい文字コードを当てる」枠を越え、[[符号化]]の復元経路そのものを推定する、といった応用も考えられます。たとえば、壊れたバイト列に対して、 [[Shift_JIS]] として読み取った場合、あるいは [[EUC-JP]] として読み取った場合のそれぞれの文脈的妥当性を示し、どの変換段階で破損が生じた可能性が高いかを説明しながら復元を補助するといった具合です。ただしこの種の[[生成モデル]]はもっともらしい仮説を自然に作り出してしまうため、過剰な“理屈付け”による誤誘導を避ける設計と[[利用者]]側の知識が不可欠となります。

[635] 
[[アーカイブ]]的な観点では、単にテキストを判定するだけでなく、当時のシステム全体 ([[オペレーティングシステム]]、[[フォント]]、入出力システム、[[アプリケーション]]固有の符号化規則など) を含む実行環境の再現を重視する考え方もあります。これは、[[フォント]]の[[文字コード]]情報が不明確なまま利用された (そして現在も明確になっていない) [[HTML]] や [[RTF]] 文書など、[[21世紀]]初頭頃 ([[平成時代]]半ば頃) までに製作された[[文書]]群の復元において特に重要です。この種の資料では、符号化判定器だけで完結するのではなく、使用されていた[[フォント]]が暗黙に前提とした[[符号]]の体系や符号化モデル、[[アプリケーション]]固有の制限や不具合まで含めて推測する必要があります。[[機械学習]]とエミュレーション技術を組み合わせることで、当時の実環境に近い“総合的な推定”を行うような高度な仕組みも将来的には可能となるでしょうが、これもまたコストに対して需要が限られているため実現までの道程は易くないでしょう。





** 実装

*** 出現頻度等による実装

[176] 出現頻度等による実装:

[REFS[

- [35] [CITE[[[UniversalCharDet]]]] の系譜
- [36] 
[CITE@en[[[GitHub]] - chomechome/charamel: 🌏 Truly Universal Encoding Detection in Python 🌎]], [TIME[2025-05-19T12:46:16.000Z]] <https://github.com/chomechome/charamel>
- [37] 
[CITE@en[GitHub - jawah/charset_normalizer: Truly universal encoding detector in pure Python]], [TIME[2025-05-19T12:51:46.000Z]] <https://github.com/jawah/charset_normalizer>
- [40] 
[CITE@en-US[Charset Detection | ICU Documentation]], [TIME[2025-04-15T18:50:10.000Z]], [TIME[2025-05-19T13:56:04.594Z]] <https://unicode-org.github.io/icu/userguide/conversion/detection.html>
- [41] 
[CITE@en[GitHub - hsivonen/shift_or_euc: Detects among the Japanese legacy encodings]], [TIME[2025-05-19T13:59:56.000Z]] <https://github.com/hsivonen/shift_or_euc>
-- [62] 
[[日本語]]系[[文字コード]]の判定
-
[91] [CITE@en[google/compact_enc_det: compact_enc_det - Compact Encoding Detection]]
([TIME[2016-07-30 15:05:47 +09:00]])
<https://github.com/google/compact_enc_det>
-- [42] 
[CITE@en[GitHub - google/compact_enc_det: compact_enc_det - Compact Encoding Detection]], [TIME[2025-05-19T14:08:52.000Z]] <https://github.com/google/compact_enc_det/>
-
[45] 
[CITE@en-US[Encode::Guess::Educated - do something - metacpan.org]], [TIME[2025-05-20T15:01:04.000Z]] <https://metacpan.org/pod/Encode::Guess::Educated>
-[81] 
[CITE@en[GitHub - vlm/zip-fix-filename-encoding: Fix cyrillic character encoding of filenames inside zip archives]], [TIME[2025-05-16T10:03:38.000Z]] <https://github.com/vlm/zip-fix-filename-encoding>
-- [144] 
[CITE@en[zip-fix-filename-encoding/src/runzip.c at master · vlm/zip-fix-filename-encoding · GitHub]], [TIME[2025-05-24T14:05:58.000Z]] <https://github.com/vlm/zip-fix-filename-encoding/blob/master/src/runzip.c>
-- [61] 
[[キリル文字]]系[[文字コード]]の判定
- [84] [CITE[Wayback Machine]], [TIME[2025-06-02T11:58:14.000Z]] <https://web.archive.org/web/20250601053528/https://shoshia.tripod.com/pub/webconv.zip>
-- [64] [CODE[GEO-CONV.PL]]
--- [65] [CODE[&analyze]]
---- [66] >>64 は[[ジョージア文字]]の変換器ですが、その改造元は[[キリル文字]]の変換器で、
(おそらく改変されていない)この関数は[[キリル文字]]の[[文字コード]]を出現頻度で推定するものです。
[[注釈]]によると
[[Stefan Mashkevich]]
が[TIME[1998-11-26]]に開発したものです。
KOI8, DOS866, WIN1251, ISO8859-5, MAC に対応しています。
- [67] 
[CITE@en[Universal online Cyrillic decoder - recover your texts]], [[Petko Yotov]], [TIME[2025-06-04T07:48:52.000Z]] <https://2cyr.com/decode/>
- [73] 
[CITE@en-US[Encode::Detect::CJK - A Charset Detector, optimized for EastAsia charset and website content - metacpan.org]], [TIME[2025-06-25T08:14:27.000Z]] <https://metacpan.org/pod/Encode::Detect::CJK>
- [77] 
[[チベット文字の文字コード]]にも[[チベット文字]]の[[符号]]の判定手法についてあり
- [647] 
[CITE@ja[エンコーディング自動検出の「その先」を、バイト列が教えてくれた]], [TIME[2026-02-26T04:17:34.000Z]] <https://zenn.dev/dress_code/articles/chardet-high-byte-ratio>


]REFS]

-*-*-

[3] [[universalchardet]] は、 [[Mozilla]] が [[Webページ]]の表示のために開発したものです。
多くの[[プラットフォーム]]に移植されて使われています。

[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 
[CODE[iso-8859-5]] 
koi8-r
[CODE[windows-1251]]
x-mac-cyrillic ibm866 ibm855 iso-8859-7 
[CODE[tis-620]]
windows-1253
iso-8859-8 windows-1255 windows-1252

;;
[6] 
データだけで未実装:
[CODE[iso-8859-2]]
[CODE[windows-1250]]

-*-*-

[276] 
[DFN[[CITE[compact_enc_det]]]] ([DFN[[CITE[ced]]]])
[SRC[>>91]]
は、
[[Google]] による[[文字コードの判定]]の[[オープンソース]]ライブラリーです。

[277] 
[CITE[Google Chrome]] で採用されています。 [[Google]] 社内の[[検索]]や [CITE[Gmail]]
などでも使われていると言われています。

[278] 
この種のライブラリーの中でも精度は高いです。 [[Google検索]]で使われる
[[Google]] 社内の世界最大規模の [[Webページ]]データベースの解析の成果が反映されていると見られます。
ソースコード中でもいろいろな調整が入っている様子が窺えます。

[279] 
ただ逆に言えば[[オープンソース]]とはいえ [[Google]] 社員以外がこれを改善する改変を行うことは困難で、
そのまま使うか、他のソフトウェアの改善のヒントに使うくらいしかできません。

-*-*-

[82] 
[DFN[[CITE[Charamel]]]]
は [[Python]] 用[[ライブラリー]]です。[[機械学習]]によって [[Python]]
が標準で対応するすべての[[符号化]]に対応したと謳っています。
[SRC[>>36]]

[83] 
実際に判定させてみると、他の判定器と比べて精度は今ひとつのようにも思われます。
その中には類縁の他の[[符号化]]と判断されたものがあり、
使用している[[文字]]次第でどちらとも判定できるので誤判定ではないと言えるものもありますが、
それらを除外しても不一致が多いように感じられます。
[[機械学習]]の方法による不透明なバイナリーデータを判定に用いているため、
改善も困難と思われます。

[85] 
付属の試験データ [SRC[>>31]]
は実際の [[Webページ]]らしきものやその他の[[テキスト]]データが含まれますが、
各[[文字コード]]には機械的に変換したものと見られます。
中には[[非ASCII文字]]が1つも含まれないデータしかない[[符号化]]もあり、
試験データとして精査されたものとは思えません。


@@
[88] 
[CITE@en[Expose apparent_encoding_confidence. by martinblech · Pull Request #1796 · psf/requests · GitHub]], [TIME[2025-10-19T13:06:53.000Z]] <https://github.com/psf/requests/pull/1796>

*** 符号構造のみによる実装


[54] [[符号構造]]のみによる実装:

[REFS[

-
[63] 
[CITE[null]], [TIME[2008-05-10T18:15:22.000Z]], [TIME[2025-05-24T14:10:44.885Z]] <http://openlab.ring.gr.jp/Jcode/Jcode.pm#:~:text=sub%20getcode>
- 
[44] 
[CITE@en-US[Encode::Guess - Guesses encoding from data - metacpan.org]], [TIME[2025-05-20T14:53:40.000Z]] <https://metacpan.org/pod/Encode::Guess>
-
[72] 
[CITE@en-US[Encode::HanDetect - Cross-encoding, cross-variant Chinese decoder - metacpan.org]], [TIME[2025-06-25T08:00:21.000Z]] <https://metacpan.org/pod/Encode::HanDetect>
--[74] [CITE@en-US[HanDetect.pm - metacpan.org]], [TIME[2003-06-27T04:53:28.000Z]], [TIME[2025-06-25T08:15:33.569Z]] <https://metacpan.org/module/Lingua::ZH::HanDetect/source>
-
[53] 
[CITE@ja[文字エンコーディング判定スクリプト - t_komuraの日記]], [TIME[2025-05-21T12:18:53.000Z]] <https://t-komura.hatenadiary.org/entry/20091220/1261305552>
-
[75] 
[CITE@en-US[Encode::Multibyte::Detect - detect multibyte encoding - metacpan.org]], [TIME[2025-06-25T08:18:04.000Z]] <https://metacpan.org/pod/Encode::Multibyte::Detect>
-
[602] 
[CITE@ja[Common Lisp と 日本語 と 文字コード]], [[Masayuki Onjo]], [TIME[2009-07-13T13:12:16.000Z]], [TIME[2025-12-05T15:30:49.195Z]] <https://lispuser.net/commonlisp/japanese.html#sec-2.1>
--
[603] 
[CITE[download]], [TIME[2008-08-20T09:01:26.000Z]], [TIME[2025-12-05T15:31:34.509Z]] <http://www.honeyplanet.jp/download.html#libguess>
--
[601] 
[CITE@en[GitHub - zqwell/guess: common lisp porting of libguess-1.0 that is a character set detection library.]], [TIME[2025-12-05T15:29:02.000Z]] <https://github.com/zqwell/guess>
-- [604] 
[CITE@en[GitHub - kaniini/libguess: character set guessing library]], [TIME[2025-12-05T15:35:45.000Z]] <https://github.com/kaniini/libguess>
- [560] 
[CITE@en[Some Node utility functions for aggregating byte information about Buffers · GitHub]], [TIME[2025-12-30T10:14:30.000Z]] <https://gist.github.com/rossj/6e31df6933636c2c7fb1bcc6ac97c72e>


]REFS]

[76] [CITE[LV Homepage (in Japanese)]], [TIME[2025-06-25T14:34:54.000Z]], [TIME[2001-01-19T05:51:42.277Z]] <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] 
[CITE@en[Add UTF-7 to replacement encoding list? / Encoding sniffing · Issue #68 · whatwg/encoding]], [TIME[2025-06-17T03:18:44.000Z]] <https://github.com/whatwg/encoding/issues/68>

[71] 
[CITE@en[Encoding: make it clear sniffing for UTF-8 is not acceptable by annevk · Pull Request #14455 · web-platform-tests/wpt · GitHub]], [TIME[2025-06-17T03:20:29.000Z]] <https://github.com/web-platform-tests/wpt/pull/14455>

[199] [CITE@ja[Escape Codec Library: ecl.js]], [TIME[2012-04-16T04:12:06.000Z]], [TIME[2025-11-19T14:41:59.833Z]] <https://www.junoe.jp/downloads/itoh/enc_js.shtml>

[198] [CITE@ja[ISO-2022-JPとSJISとEUCJP(とUTF-8)をざっくり判別するアルゴリズム - うならぼ]], [TIME[2025-11-19T14:38:09.000Z]] <https://unarist.hatenablog.com/entry/2017/02/28/205401>


* 品質検査

[590] 
判定器の性能評価はいくつかの観点がありますが、動作速度やメモリー消費量などの一般的なソフトウェアの評価指標はもちろんとして、[[文字コードの判定]]の精度が最重要となります。

[591] 
ところが判定精度は評価が困難です。外部的な [CODE[charset]] 指定や[[データ形式]]で定められた [CODE[<meta charset>]] 等の記述を利用する場合の挙動は容易に検査可能ですし、同じ条件ならすべての判定器が必ず同じ回答を返すべきであり、そうでないなら不具合だと断言できます。判定器の実装も決定的で安定した手法に違いないでしょうから、あまり多くのパターンを用意せずとも品質を確認できます。ところがそのような付加情報のない[[バイト列]]の[[文字コードの判定]]問題は、[[発見的]]手法の積み重ねで実装ごとに挙動が異なり、どの実装も完璧ではないことが前提となります。ある試験データの挙動から他の試験データの挙動を予測することは簡単ではなく、どのような試験データをどれだけ用意したかによって見かけの精度がまったく変わってしまいます。

[592] 
対象となる分野の試験データを各種満遍なく大量に確保できれば良いのですが、どのように集めれば「満遍なく」と言えるのかすらも簡単には答えられません。そして、 [[UTF-8]] 化が進んでいる現在では対象データを探すのはどんどん難しくなっています。いっとき確保できたとしても、大量のデータを永続的に、しかも権利関係のトラブルなく開発関係者間で保持し続ける難しさも、継続的な開発の障害となります。

[593] 
[[Webページ]]の場合、 [[Internet Archive]] の過去のサイトから実際のデータを試験データとして確保できます。ただし、古い [[Webサイト]]の [[URL]] を見つけて、人手で正しい[[文字コード]]を確認して「正解」データを整備する必要があります。古いサイトだけでなく実稼働サイトも試験データとすることで幅広い時代の言語に対応可能か検査したいところですが、実サイトは継続性に不安が残ることと、更新によって内容が変わってしまう可能性が常にあることに気をつけなければなりません。 [[Internet Archive]] に最新の複製を保存しつつ「正解」データを作るのが良いでしょう。

[594] 
[[ZIPファイル]]の場合、一般公開されずに流通しているものが多いと思われますが、それらを収集して試験データとして利用することは無理だと思った方が良いでしょう。公開ファイルは [[Webページ]]と同じ要領で [[Internet Archive]] や実稼働サイトから探して使うことになります。近年ではどこの[[国]]でも[[政府]]や[[地方自治体]]で[[オープンデータ]]の公開サイトを用意しており、 [[ZIPファイル]]で配布されていることが多いです。 [[UTF-8]] 化が進んでいますが、従来[[文字コード]]の [[ZIPファイル]]も未だに大量に生成され続けています。



-*-*-

[599] 
各種の判定器の実装は、最低限の動作検証のための短い試験データを用意していたり、注釈やドキュメントに実例を示していたりすることがあります。このようなデータは実利用例そのものではないにせよ、各実装者の取り組んだ問題をコンパクトに表現したものであり、きっかけとなった実際の課題を反映しているはずです。実世界の事例そのものだけでなく、こうしたものも試験データとして有益と考えられます。

[600] 
ただし、こうしたものは極端に短く単体での出現は非現実的とも考えられますから、それに過度に適応するのも考えものです。


-*-*-

[595] 
各種の判定器の実装は、
テストデータを用意、公開しているものもありますが、
いずれも分量はあまり多くありません。 [[Unicode]] の原文から変換されて作られたらしきものも多いです。中にはおよそ実用されたとは思えない[[自然言語]]と[[文字コード]]の組み合わせの試験ファイルも含まれていたりします。

[596] 
また、 [CITE[Wikipedia]] の各言語の [[Unicode]] の文章を各種の[[文字コード]]に変換して、それを試験データとして使ったという報告も見られます。

[597] 
こうした試験データを使った性能評価は、実世界データの確保が難しい以上、やむを得ないと言わざるを得ないものではあります。限定的で人工的とはいえ、確かにある種の入力に対して正しく[[文字コード]]を判定できると確認できるのなら、それは当該ソフトウェアの品質検査として無駄とは言えません。ただ、そうした制限付きで恣意的な試験データによって他の判定器と性能を比較し、あちらの精度はどれくらいでこちらの精度はどれくらいだ、などと優位性を語るのは如何なものかとも思います。

[598] 
確かに精度が低いよりは精度が高い方が優れているのかもしれませんが、それは他の性能指標や機能性 ([[文字コード]]のカバー範囲など)、あるいは開発の継続可能性 (改善・修正のし易さなど) 等々とのトレードオフでもあるでしょう。
たとえ人工的な文書集合での精度が良いとしても、
その集合が対象分野の実データの性質と乖離していれば、
実践での精度とは違う意味のない数値にしかならないことも注意が必要です。
重要なのは精度の数値自体ではなく、利用目的への適合性です。

-*-*-

[607] 
各種判定器のソースコードをよく見ると、判定条件や状態機械の遷移条件などが間違っているのではないかと思われる事例もちらほら見られます。その性質上、境界値などのちょっとした不具合も全体の複雑さに埋もれて露見しにくくなります。多少であれば総合的な影響は少ないものの、短い入力や特殊な文章などに対する反応が悪くなるおそれがありますから、いろいろな試験データで動作を確認することが重要です。






** 頻度解析等の手法のためのテストデータ

[REFS[

- [7] 
[CITE@en[gecko-dev/extensions/universalchardet/tests at master · mozilla/gecko-dev · GitHub]], [TIME[2025-05-17T09:04:18.000Z]] <https://github.com/mozilla/gecko-dev/tree/master/extensions/universalchardet/tests>
-- [8] [[MPL]] 2
- [9] [CITE@en[juniversalchardet/data at master · seratch/juniversalchardet · GitHub]], [TIME[2025-05-18T03:30:23.000Z]] <https://github.com/seratch/juniversalchardet/tree/master/data>
-- [10] [[MPL]] 1.1 / [[GPL]] 2+ / [[LGPL]] 2.1+
- [11] 
[CITE@en[juniversalchardet/src/test/resources at main · albfernandez/juniversalchardet · GitHub]], [TIME[2025-05-18T03:36:18.000Z]] <https://github.com/albfernandez/juniversalchardet/tree/main/src/test/resources>
-- [12] [[MPL]] 1.1 / [[GPL]] 2+ / [[LGPL]] 2.1+
-- [13] >>9 を含み、更に追加
- [14] 
[CITE@en[ude/src/Tests/Data at master · errepi/ude · GitHub]], [TIME[2025-05-18T03:40:02.000Z]] <https://github.com/errepi/ude/tree/master/src/Tests/Data>
-- [15] 「[[MPL]] 1.1 / [[GPL]] 2+ / [[LGPL]] 2.1+」、
「Wikipedia と同じ」、
「The Project Gutenberg と同じ」
が混在
-- [16] >>9 を含み、更に追加
- [17] 
[CITE@ja[test · master · uchardet / uchardet · GitLab]], [TIME[2025-05-18T04:21:47.000Z]] <https://gitlab.freedesktop.org/uchardet/uchardet/-/tree/master/test?ref_type=heads>
-- [18] [[MPL]] 1.1 / [[GPL]] 2+ / [[LGPL]] 2.1+
- [19] 
[CITE@en[rust-chardet/tests/data at master · thuleqaid/rust-chardet · GitHub]], [TIME[2025-05-18T05:01:25.000Z]] <https://github.com/thuleqaid/rust-chardet/tree/master/tests/data>
-- [20] [[LGPL]] 3
- [21] [CITE@en[chardet/tests at main · chardet/chardet · GitHub]], [TIME[2025-05-18T05:10:41.000Z]] <https://github.com/chardet/chardet/tree/main/tests>
-- [22] 不自由なものを含む
---
[28] 
[CITE@en[problematic licensing of /tests? · Issue #231 · chardet/chardet]], [TIME[2025-05-19T06:27:37.000Z]] <https://github.com/chardet/chardet/issues/231>
--- [27] 
[CITE@en[Documentation licensed only to non-commercial and personal use found · Issue #271 · chardet/chardet]], [TIME[2025-05-19T06:24:05.000Z]] <https://github.com/chardet/chardet/issues/271>
- [29] 
[CITE@en[GitHub - Ousret/char-dataset: Public dataset used to challenge Charset-Normalizer]], [TIME[2025-05-19T08:37:52.000Z]] <https://github.com/Ousret/char-dataset>
-- [30] ライセンス不明
- [31] 
[CITE@en[charamel/tests/fixtures at master · chomechome/charamel · GitHub]], [TIME[2025-05-19T11:59:39.000Z]] <https://github.com/chomechome/charamel/tree/master/tests/fixtures>
-- [32] [[Apache 2.0]] となっているが、出所の怪しげなファイルもある
-- [33] [[Git LFS]]
-- [34] 機械的に変換したファイルが多い?
- [46] 
[CITE@en[compact_enc_det/compact_enc_det/compact_enc_det_unittest.cc at master · google/compact_enc_det · GitHub]], [TIME[2025-05-21T06:26:33.000Z]] <https://github.com/google/compact_enc_det/blob/master/compact_enc_det/compact_enc_det_unittest.cc>
-- [47] [[Apache 2.0]]
-- [48] [[C++]] ソースコードに埋め込まれている
- [605] 
[CITE@en[libguess/src/tests/testbench at master · kaniini/libguess · GitHub]], [TIME[2025-12-05T15:33:34.000Z]] <https://github.com/kaniini/libguess/tree/master/src/tests/testbench>
-- [606] [[BSD3]]

]REFS]


* 関連

[55] [[文字コード選択メニュー]]

* メモ


[80] 
[CITE@en[How to reliably guess the encoding between MacRoman, CP1252, Latin1, UTF-8, and ASCII - Stack Overflow]], [TIME[2025-10-18T08:36:44.000Z]] <https://stackoverflow.com/questions/4198804/how-to-reliably-guess-the-encoding-between-macroman-cp1252-latin1-utf-8-and>


- [51] 
[CITE@ja[mb_detect_encoding() は文字コード判定として使用できるか(その1) - t_komuraの日記]], [TIME[2025-05-21T12:15:39.000Z]] <https://t-komura.hatenadiary.org/entry/20090615/1245078430>
-- [50] 
[CITE@ja[mb_detect_encoding() は文字コードの妥当性検証として使用できるか(その2) - t_komuraの日記]], [TIME[2025-05-21T12:15:09.000Z]] <https://t-komura.hatenadiary.org/entry/20090621/1245595484>
-- [52] 
[CITE@ja[mb_detect_encoding() は文字コードの妥当性検証として使用できるか(その3) - t_komuraの日記]], [TIME[2025-05-21T12:17:54.000Z]] <https://t-komura.hatenadiary.org/entry/20090705/1246802467>





[49] [CITE@en['''['''ptexenc''']''' 入力ファイルの文字コードの自動判定 · Issue #142 · texjporg/tex-jp-build]], [TIME[2025-05-21T12:13:06.000Z]] <https://github.com/texjporg/tex-jp-build/issues/142>









[89] [CITE@en[21990 – When a rare EUC-JP character is present, explicitly (and correctly) labelled EUC-JP document is mistreated as Shift_JIS]], [TIME[2025-11-16T05:48:11.000Z]] <https://bugs.webkit.org/show_bug.cgi?id=21990>

[90] 
[CITE@en[16482 – Hook up ICU's encoding detector and add a boolean param to Settings and WebPreferences]], [TIME[2025-11-16T05:50:12.000Z]] <https://bugs.webkit.org/show_bug.cgi?id=16482>
