MySQL — потерянные буквы 'ш' и 'И' — решение
Недавно пришлось восстанавливать сайт на Wordpress, и дамп MySQL'ной базы оказался дважды перекодирован из Windows-1251 в UTF-8. После того, как я его перекодировал взад, оказалось, что из русского текста пропали две буквы: 'ш' и 'И' — на их месте стояли кракозябылы.
Порылся в сети — оказалось, что бага известная и периодически случающаяся. И большей частью с ней борются, практически, вручную, по крайней мере мне не удалось найти никакого скрипта, который бы я мог использовать для решения этой проблемы. В итоге, я написал свой :).
Скачать: SHI-convert.zip (1 Кб).
Скрипт будет работать, скорее всего, только для двойного преобразования Windows-1251 → UTF-8. Результат работы скрипта — текст в UTF-8 с поставленными на место буквами 'ш' и 'И'.
Шлите ваши комментарии :).
<?php
/**
Восстанавливатель текстов, подвергшихся двойной перекодировки
из Windows-1251 в UTF-8. Казалось бы, что сложного в том, чтобы
сделать обратное преобразование? Однако, проблема в том, что
по неизвестным причинам в исходном тексте теряются две буквы:
'ш' и 'И'.
Особенно часто этот глюк встречается при экспорте базы из MySQL
при криво настроенных свойствах кодировки таблиц и экспорта.
Как использовать:
php SHI-converter.php {имя файла} > {имя нового файла}
Комментарии, предложения, замечания?
http://outcorp-ru.blogspot.com/2011/08/mysql.html
Copyleft, Стас Давыдов и Outcorp, 2011.
stas@motivateme.ru, http://stasdavydov.com, http://outcorp-ru.blogspot.com/
*/
define("DEBUG", FALSE);
function get_bytes($str) {
$len = strlen($str);
$bytes = '';
for($i = 0; $i < $len; $i++) {
$bytes .= sprintf('%2X', ord($str[$i]));
if ($i < $len - 1)
$bytes .= ' ';
}
return $bytes;
}
function fix_bytes(&$str, $start = 0, $len = 0) {
if (ord($str[$start + $len]) == 0xD0) {
$str[$start + $len + 1] = chr(0x98);
} else if (ord($str[$start + $len]) == 0xD1) {
$str[$start + $len + 1] = chr(0x88);
} else {
$str[$start + $len] = ' ';
}
}
function fix_string(&$s) {
$converted = @iconv('utf-8', 'windows-1251', $s);
if (strlen($converted) > 0) {
$converted = iconv('windows-1251', 'utf-8', $converted);
$sub = strlen($converted);
$start = strpos($s, $converted);
if(DEBUG)
echo $converted;
if(DEBUG) {
echo '['.get_bytes(substr($s, $start + $sub)).']'."\n";
}
fix_bytes($s, $start, $sub);
} else {
if (DEBUG)
echo '['.get_bytes($s).']'."\n";
fix_bytes($s);
}
}
if ($_SERVER['argc'] != 2) {
echo 'Usage: '.pathinfo(__FILE__, PATHINFO_FILENAME).".php <name of file to recover>\n";
exit;
}
$filename = $_SERVER['argv'][1];
$str = file_get_contents($filename);
$utf8str = iconv('utf-8', 'windows-1251', $str);
foreach(preg_split('/( |\t)/', $utf8str) as $s) {
while(! mb_check_encoding($s, 'utf-8')) {
fix_string($s);
if (DEBUG)
echo $s."\n";
}
if (! DEBUG)
echo $s.' ';
}
?>
4 комментария:
Такой изврат с разбиением текста на слова и последовательный прогон через mb_check_encoding связан с тем, что простой заменой тут не обойтись - фиг его знает, где еще может встретиться нужная нам последовательность символов в испорченных 'И' и 'ш' - мультибайт ведь.
Режим DEBUG оставлен на случай, если пропадут еще какие-нибудь символы - к ним так легче будет подобрать восстанавливающий паттерн.
Спасибо, помогло :)
Очень помогло! Два дня голову ломал! Огромное спасибо!
Очень помогло! Два дня голову ломал! Огромное спасибо!
Отправить комментарий