Как стать автором
Поиск
Написать публикацию
Обновить

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

Во время работы над импортом данных из 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 символов, взятых из середины переданной строки. Это сделано для увеличения производительности на больших текстах.


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

Советы и замечания очень приветствуются. Спасибо.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.