PHPでのテキストエンコーディングの定義、パート2-Bigram

前回の記事では、文字の分布頻度に基づいてテキストエンコーディングを自動的に決定するアルゴリズムが実装されました。 コメントでは、彼らは注意しました :バイグラム(トライグラム)を使用すると、結果はより正確になります。 それから私は却下し、彼らは言う、そして単一の文字で良い結果が得られる。 しかし、アルゴリズムに信頼性と精度を追加することは素晴らしいことだと思いました。特に、単一の文字の代わりにバイグラムを使用するので、食べる必要はあまりありません。



カットの下-バイグラム、ソースコード、およびその作業の結果でのアルゴリズムの実装例。





アルゴリズムの説明





いつものように、私たちはシングルバイトのロシア語エンコーディングでのみ動作します。 UTF-8を決定するためのこのようなアルゴリズムを記述する意味はありません。非常に単純に決定されます。

$str_utf8 = ' '; $str_cp1251 = iconv('UTF-8', 'Windows-1251', $str_utf8); var_dump(preg_match('#.#u', $str_utf8)); var_dump(preg_match('#.#u', $str_cp1251));
      
      





 m00t@m00t:~/workspace/test$ php detect_encoding.php int(1) int(0)
      
      







そのため、かなり大きなロシア語のテキストを取り、文字の頻度の代わりに文字のペアの頻度を測定します(私は伝統的に戦争と平和を取りました)。 そのようなものが得られます(ここでは頻度は示されていませんが、テキスト内の参照の数は実際には同じです):

 <?php return array ( '' => 3, '' => 1127, '' => 5595, '' => 1373, '' => 3572, '' => 1483, '' => 0, '' => 1931, .... '' => 1325, '' => 2439, '' => 1, '' => 1, '' => 284, '' => 70, '' => 254, '' => 0, '' => 0, '' => 0, '' => 0, '' => 185, '' => 283, );
      
      







次に、このケースをすべての必要なエンコーディングに変換し、異なる大文字と小文字のオプションを追加します(同時に、参照の数を頻度に変換します)。

 <?php return array ( '' => 2.5816978277594E-6, '' => 2.5816978277594E-6, '' => 2.5816978277594E-6, '' => 2.5816978277594E-6, '' => 0.00096985781729497, '' => 0.00096985781729497, '' => 0.00096985781729497, '' => 0.00096985781729497, '' => 0.0048148664487714, '' => 0.0048148664487714, '' => 0.0048148664487714, '' => 0.0048148664487714, ... '' => 0, '' => 0, '' => 0, '' => 0, '' => 0, '' => 0, '' => 0, '' => 0, '' => 0, '' => 0, '' => 0, '' => 0, '' => 0.0001592046993785, '' => 0.0001592046993785, '' => 0.0001592046993785, '' => 0.0001592046993785, '' => 0.00024354016175197, '' => 0.00024354016175197, '' => 0.00024354016175197, '' => 0.00024354016175197, );
      
      





これらのファイルのうち、cp1251、koi8-r、iso8859-5の3つのファイルを取得しました。



さて、未知のテキストのエンコーディングを見つける必要があるとき、それを調べ、すべての文字のペアを分離し、各エンコーディングの「重み」に、すでに生成されたスペクトルからこの文字のペアの周波数を追加します。



作業結果



コメント付き配列-対応するエンコーディングのテキスト内の文字ペアの合計重みを、すべての送信の合計で割った値( test_detect_encoding.php:21を参照 )。 つまり これらは、テキストがこのエンコーディングに含まれている確率であると言えます。

 $data = iconv('UTF-8', 'iso8859-5', '  '); /* array(3) { ["windows-1251"]=> float(0.071131587263965) ["koi8-r"]=> float(0.19145038318717) ["iso8859-5"]=> float(0.73741802954887) } */ $data = iconv('UTF-8', 'windows-1251', '  '); /* array(3) { ["windows-1251"]=> float(0.95440659551352) ["koi8-r"]=> float(0.044353550201316) ["iso8859-5"]=> float(0.0012398542851665) } */ $data = file_get_contents('test/cp1251_1.html'); //  -    cp1251 /* array(3) { ["windows-1251"]=> float(0.78542385878465) ["koi8-r"]=> float(0.18514302234077) ["iso8859-5"]=> float(0.029433118874583) } */
      
      







ご覧のように、非常に良い結果が得られます-たとえ小さな線であっても、正しいエンコーディングはほぼ一桁のリードをもたらします。



3つのシングルバイトエンコーディング(もちろんロシア語用)で生成されたスペクトルを持つすべてのソースは、githubからダウンロードできます。 コードはたった100行しかないため、意図的にすべてを再利用可能なlibの形で作成しませんでした。 誰かがそれを必要とする場合、彼は自分が好きな方法と、これまたはその使用されたフレームワークを課す方法を自分で調整することができます。



All Articles