Кодировка файлов

Как определить в какой кодировке записан файл?

Анализировать мы будем содержимое файлов с осмысленным текстом, а не просто с набором символов. Нас, естественно, будут интересовать только кодировки, относящиеся к Русскому языку. Таких кодировок семь, все они используются, понимаются броузерами, покажем какие символы используют эти кодировки. За основную кодировку примем windows-1251. Смысл данной странички задать вопрос, а можно ли нам исследовав файл на наличие символов, чётко сказать в какой кодировке сохранён данный файл.

Итак, наш алфавит в разных кодировках:

Посмотрим, как будут смотреться разные кодировки в Win:

Winабвгдеёжзийклмнопрстуфхцчшщъыьэюя
KoiБВЧЗДЕ?ЦЪЙКЛМНОПРТУФХЖИГЮЫЭЯЩШЬАС
IsoРСТУФХсЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп
MacабвгдеЮжзийклмнопрстуфхцчшщъыьэюЯ
Ibm866 Ўў?¤?с¦§ЁcЄ<¬-RЇабвгдежзийклмноп
Ibm855 ўл¬¦Ё"йу·?ЖРТФЦШбгезЄч¤ыхщ?снч?Ю
Utf-8Р°Р+Р?Р?Р?РчС'жзийкР>Р?Р?Р?РїС?С?С'С?С"С:С+С+С?С%С?С<С?С?С?С?

В тексте мы будем искать эти символы, кодировку будем определять по количеству найденных символов.

Здесь, представлены только маленькие буквы русского языка. После анализа символов можно сделать такой вывод:

  • кодировка Koi8-r (iso-ir-111), совпадает с Windows-1251, только все символы становятся в большом регистре. Наоборот, все Большие буквы становятся маленькими в Koi8-r. Пусть символы не совпадают друг с другом, но для поиска нам достаточно того, что мы знаем, кроме буквы 'ё', чётко сказать, что файл сохранён в кодировке Koi8-r или Windows-1251 нельзя, потому что их символы совпадают. Можно попробовать искать маленькие русские буквы в файле, если их будет больше, чем символов в Большом регистре, можно предположить, что файл сохранён в Windows-1251.
  • В кодировке Iso-8859-5 есть абвгдежзийклмноп, то есть 16 букв из Windows-1251.
  • В кодировке X-mac-cyrillic (X-mac-ukrainian) есть все маленькие символы из Windows-1251, кроме 'ё' и 'я', буква 'я' переходит в верхний регистр. Этот факт не даёт нам возможности со 100% гарантией сказать, что файл сохранён в кодировке Windows-1251 или X-mac-cyrillic.
  • В кодировке Ibm866 есть абвгдежзийклмноп, то есть 16 букв из Windows-1251, что совпадает с кодировкой Iso-8859-5, что для нас плохо, значит надо добавить поиск символов в большом регистре, чтобы получить отличие. Зато, с Windows-1251 есть приличное различие.
  • В кодировке Ibm855 есть бгезйлнсущы, то есть 11 букв из Windows-1251.
  • В кодировке Utf-8 нет символов из Windows-1251, то есть мы четко сможем сказать , что файл, например, сохранён в Utf-8.

Вывод: проверяя файл на наличие в нём тех или иных символов, нельзя точно сказать в какой кодировке сохранён файл. Тем не менее, всё - таки, приведём небольшую функцию по определению кодировки в файле.

// функция, выводящая кодировку файла
function search_file_kod ($path){
$charsets = array ( 'w' => 0, 'k' => 0, 'i' => 0, 'm' => 0, 'a' => 0, 'c' => 0, 'u' => 0 );
$fp = fopen ($path, "rb");
if (!$fp){ return 'error'; }
$content = fread ($fp , '1024');
fclose ($fp);

    // Windows-1251
$search_l_w = "~([\270])|([\340-\347])|([\350-\357])|([\360-\367])|([\370-\377])~s";
$search_U_w = "~([\250])|([\300-\307])|([\310-\317])|([\320-\327])|([\330-\337])~s";

    // Koi8-r
$search_l_k = "~([\243])|([\300-\307])|([\310-\317])|([\320-\327])|([\330-\337])~s";
$search_U_k = "~([\263])|([\340-\347])|([\350-\357])|([\360-\367])|([\370-\377])~s";

    // Iso-8859-5
$search_l_i = "~([\361])|([\320-\327])|([\330-\337])|([\340-\347])|([\350-\357])~s";
$search_U_i = "~([\241])|([\260-\267])|([\270-\277])|([\300-\307])|([\310-\317])~s";

    // X-mac-cyrillic
$search_l_m = "~([\336])|([\340-\347])|([\350-\357])|([\360-\367])|([\370-\370])|([\337])~s";
$search_U_m = "~([\335])|([\200-\207])|([\210-\217])|([\220-\227])|([\230-\237])~s";

    // Ibm866
$search_l_a = "~([\361])|([\240-\247])|([\250-\257])|([\340-\347])|([\350-\357])~s";
$search_U_a = "~([\360])|([\200-\207])|([\210-\217])|([\220-\227])|([\230-\237])~s";

    // Ibm855
$search_l_c = "~([\204])|([\234])|([\236])|([\240])|([\242])|([\244])|([\246])|([\250])|".
"([\252])|([\254])|([\265])|([\267])|([\275])|([\306])|([\320])|([\322])|".
"([\324])|([\326])|([\330])|([\340])|([\341])|([\343])|([\345])|([\347])|".
"([\351])|([\353])|([\355])|([\361])|([\363])|([\365])|([\367])|([\371])|([\373])~s";
$search_U_c = "~([\205])|([\235])|([\237])|([\241])|([\243])|([\245])|([\247])|([\251])|".
"([\253])|([\255])|([\266])|([\270])|([\276])|([\307])|([\321])|([\323])|".
"([\325])|([\327])|([\335])|([\336])|([\342])|([\344])|([\346])|([\350])|".
"([\352])|([\354])|([\356])|([\362])|([\364])|([\366])|([\370])|([\372])|([\374])~s";

    // Utf-8
$search_l_u = "~([\xD1\x91])|([\xD1\x80-\x8F])|([\xD0\xB0-\xBF])~s";
$search_U_u = "~([\xD0\x81])|([\xD0\x90-\x9F])|([\xD0\xA0-\xAF])~s";

if ( preg_match_all ($search_l_w, $content, $arr, PREG_PATTERN_ORDER)) { $charsets['w'] += count ($arr[0]) * 3; }
if ( preg_match_all ($search_U_w, $content, $arr, PREG_PATTERN_ORDER)){ $charsets['w'] += count ($arr[0]); }

if ( preg_match_all ($search_l_k, $content, $arr, PREG_PATTERN_ORDER)) { $charsets['k'] += count ($arr[0]) * 3; }
if ( preg_match_all ($search_U_k, $content, $arr, PREG_PATTERN_ORDER)){ $charsets['k'] += count ($arr[0]); }

if ( preg_match_all ($search_l_i, $content, $arr, PREG_PATTERN_ORDER)) { $charsets['i'] += count ($arr[0]) * 3; }
if ( preg_match_all ($search_U_i, $content, $arr, PREG_PATTERN_ORDER)){ $charsets['i'] += count ($arr[0]); }

if ( preg_match_all ($search_l_m, $content, $arr, PREG_PATTERN_ORDER)) { $charsets['m'] += count ($arr[0]) * 3; }
if ( preg_match_all ($search_U_m, $content, $arr, PREG_PATTERN_ORDER)){ $charsets['m'] += count ($arr[0]); }

if ( preg_match_all ($search_l_a, $content, $arr, PREG_PATTERN_ORDER)) { $charsets['a'] += count ($arr[0]) * 3; }
if ( preg_match_all ($search_U_a, $content, $arr, PREG_PATTERN_ORDER)){ $charsets['a'] += count ($arr[0]); }

if ( preg_match_all ($search_l_c, $content, $arr, PREG_PATTERN_ORDER)) { $charsets['c'] += count ($arr[0]) * 3; }
if ( preg_match_all ($search_U_c, $content, $arr, PREG_PATTERN_ORDER)){ $charsets['c'] += count ($arr[0]); }

if ( preg_match_all ($search_l_u, $content, $arr, PREG_PATTERN_ORDER)) { $charsets['u'] += count ($arr[0]) * 3; }
if ( preg_match_all ($search_U_u, $content, $arr, PREG_PATTERN_ORDER)){ $charsets['u'] += count ($arr[0]); }

arsort ($charsets);
$key = key($charsets);
if ( max ($charsets)==0 ){ return 'unknown'; }
elseif ( $key == 'w' ){ return 'win'; }
elseif ( $key == 'k' ){ return 'koi'; } 
elseif ( $key == 'i' ){ return 'iso'; } 
elseif ( $key == 'm' ){ return 'mac'; } 
elseif ( $key == 'a' ){ return 'ibm866';} 
elseif ( $key == 'c' ){ return 'ibm855';} 
elseif ( $key == 'u' ){ return 'utf8'; } 
}

    // выведем кодировку файла file.txt
print search_file_kod ('file.txt');

.