Search
Write a publication
Pull to refresh

Автоматическое определение кодировки русского текста

Во время работы над импортом данных из csv для сервиса дзен-мани передо мной встала задача автоматического определения кодировки содержащихся в загруженном пользователем файле данных.

Поискав в гугле варианты решения, я с удивлением обнаружил что наиболее продвинутый алгоритм основан на использовании словарей недопустимых комбинаций символов. Мне это показалось не самым оптимальным решением и я написал собственную функцию определения кодировки.

Смысл алгоритма довольно-таки прост, он основывается на следующих наблюдениях:


  • Соотношение гласных к согласным примерно одинаково для всех текстов одного и того же языка (для русского — около 1 к 3)
  • В неправильно закодированном тексте это соотношение нарушается
  • В неправильно закодированном тексте уменьшается количество национальных символов


таким образом были выведены два критерия, по которым можно было оценивать успешность подбора кодировки:
  • количество национальных символов в тексте должно приближаться к количеству символов в тексте
  • соотношение национальных гласных к согласным должно приближаться к частотным характеристикам языка


в результате реализации был получен следующий код:
  function detect_encoding($string, $pattern_size = 50)
  {
    $list = array('cp1251', 'utf-8', 'ascii', '855', 'KOI8R', 'ISO-IR-111', 'CP866', 'KOI8U');
    $c = strlen($string);
    if ($c > $pattern_size)
    {
      $string = substr($string, floor(($c - $pattern_size) /2), $pattern_size);
      $c = $pattern_size;
    }
    $reg1 = '/(а|у|е|ы|о|э|ю|и|я)/i';
    $reg2 = '/(й|ц|к|н|г|ш|щ|з|х|ъ|ф|в|п|р|л|д|ж|б|ь|т|м|с|ч)/i';

    $mk = 1000000;
    $enc = 'ascii';
    foreach ($list as $item)
    {
      $sample1 = @iconv($item, 'UTF-8', $string);
      $gl = @preg_match_all($reg1, $sample1, $arr);
      $sl = @preg_match_all($reg2, $sample1, $arr);
      if (!$gl || !$sl) continue;
      $k = abs(3 - ($sl / $gl));
      $k += $c - $gl - $sl;
      if ($k < $mk)
      {
        $enc = $item;
        $mk = $k;
      }
    }
    return $enc;
  }

* This source code was highlighted with Source Code Highlighter.
Параметры:
  • $string — строка в неизвестной кодировке.
  • $pattern_size — если строка больше этого размера, то определение кодировки будет производиться по шаблону из $pattern_size символов, взятых из середины переданной строки. Это сделано для увеличения производительности на больших текстах.


Как всегда — автор не несёт никакой ответственности за использование этого кода ;)

Советы и замечания очень приветствуются. Спасибо.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.