У меня есть следующая проблема кодирования символов, так как мне удалось сохранить данные с различной кодировкой символов в моей базе данных (UTF8). В приведенном ниже коде и выводах показаны две строки примеров и их вывод. 1 из них нужно будет заменить на UTF8, а другой уже есть.
Как я / должен ли я проверять, следует ли кодировать строку или нет? например, мне нужно, чтобы каждая строка выводилась правильно, поэтому как проверить, является ли она уже utf8, или нужно ли ее преобразовать?
Я использую PHP 5.2, таблицы mysql myisam:
CREATE TABLE IF NOT EXISTS `entities` ( .... `title` varchar(255) NOT NULL .... ) ENGINE=MyISAM DEFAULT CHARSET=utf8; <?php $text = $entity['Entity']['title']; echo 'Original : ', $text."<br />"; echo 'UTF8 Encode : ', utf8_encode($text)."<br />"; echo 'UTF8 Decode : ', utf8_decode($text)."<br />"; echo 'TRANSLIT : ', iconv("ISO-8859-1", "UTF-8//TRANSLIT", $text)."<br />"; echo 'IGNORE TRANSLIT : ', iconv("ISO-8859-1", "UTF-8//IGNORE//TRANSLIT", $text)."<br />"; echo 'IGNORE : ', iconv("ISO-8859-1", "UTF-8//IGNORE", $text)."<br />"; echo 'Plain : ', iconv("ISO-8859-1", "UTF-8", $text)."<br />"; ?>
Original : France Télécom UTF8 Encode : France Télécom UTF8 Decode : France T l com TRANSLIT : France Télécom IGNORE TRANSLIT : France Télécom IGNORE : France Télécom Plain : France Télécom
Original : Cond Nast Publications UTF8 Encode : Condé Nast Publications UTF8 Decode : Cond?ast Publications TRANSLIT : Condé Nast Publications IGNORE TRANSLIT : Condé Nast Publications IGNORE : Condé Nast Publications Plain : Condé Nast Publications
Спасибо вам за это. Кодировка символов, и я не очень хорошо себя чувствую!
ОБНОВИТЬ:
echo strlen($string)."|".strlen(utf8_encode($string))."|"; echo (strlen($string)!==strlen(utf8_encode($string))) ? $string : utf8_encode($string); echo "<br />"; echo strlen($string)."|".strlen(utf8_decode($string))."|"; echo (strlen($string)!==strlen(utf8_decode($string))) ? $string : utf8_decode($string); echo "<br />"; 23|24|Cond Nast Publications 23|21|Cond Nast Publications 16|20|France Télécom 16|14|France Télécom
Это может быть задачей для функции mb_detect_encoding()
.
В моем ограниченном опыте с ним он не на 100% надежен, когда используется как общий «сниффер кодирования» – он проверяет наличие определенных символов и байтовых значений, чтобы сделать обоснованное предположение, – но в этом узком случае (ему нужно будет различать только между UTF-8 и ISO-8859-1), он должен работать.
<?php $text = $entity['Entity']['title']; echo 'Original : ', $text."<br />"; $enc = mb_detect_encoding($text, "UTF-8,ISO-8859-1"); echo 'Detected encoding '.$enc."<br />"; echo 'Fixed result: '.iconv($enc, "UTF-8", $text)."<br />"; ?>
вы можете получить неверные результаты для строк, которые не содержат специальных символов, но это не проблема.
Я сделал функцию, которая затрагивает все эти проблемы. Он называется Encoding :: toUTF8 ().
<?php $text = $entity['Entity']['title']; echo 'Original : ', $text."<br />"; echo 'Encoding::toUTF8 : ', Encoding::toUTF8($text)."<br />"; ?>
Вывод:
Original : France Télécom Encoding::toUTF8 : France Télécom Original : Cond Nast Publications Encoding::toUTF8 : Condé Nast Publications
Вам не нужно знать, что такое кодировка ваших строк, если вы знаете, что это либо на Latin1 (iso 8859-1), либо на Windows-1252, либо на UTF8. Строка также может содержать их смесь.
Кодирование :: toUTF8 () преобразует все в UTF8.
Я сделал это, потому что служба давала мне поток данных, все испорченные, смешивая UTF8 и Latin1 в одной строке.
Применение:
$utf8_string = Encoding::toUTF8($utf8_or_latin1_or_mixed_string); $latin1_string = Encoding::toLatin1($utf8_or_latin1_or_mixed_string);
Скачать:
http://dl.dropbox.com/u/186012/PHP/forceUTF8.zip
Я включил еще одну функцию, Encoding :: fixUFT8 (), которая исправит каждую строку UTF8, которая выглядит искаженной.
Применение:
$utf8_string = Encoding::fixUTF8($garbled_utf8_string);
Примеры:
echo Encoding::fixUTF8("Fédération Camerounaise de Football"); echo Encoding::fixUTF8("Fédération Camerounaise de Football"); echo Encoding::fixUTF8("FÃÂédÃÂération Camerounaise de Football"); echo Encoding::fixUTF8("Fédération Camerounaise de Football");
выведет:
Fédération Camerounaise de Football Fédération Camerounaise de Football Fédération Camerounaise de Football Fédération Camerounaise de Football
Другой способ, возможно, более быстрый и менее ненадежный:
echo (strlen($str)!==strlen(utf8_decode($str))) ? $str //is multibyte, leave as is : utf8_encode($str); //encode
Он сравнивает длину исходной строки и строку utf8_decoded. Строка, содержащая многобайтовый символ, имеет параметр strlen, который отличается от аналогичного strben с одним байтом.
Например:
strlen('Télécom')
должен вернуть 7 в Latin1 и 9 в UTF8
Я не пробовал ваши образцы здесь, но из прошлого опыта, есть быстрое решение для этого. Сразу после подключения к базе данных выполните следующий запрос перед запуском любых других запросов:
SET NAMES UTF8;
Это стандарт SQL Standard и хорошо работает с другими базами данных, такими как Firebird и PostgreSQL.
Но помните, что вам нужно также обеспечить декларации UTF-8 в других местах, чтобы ваше приложение отлично работало. Следуйте за быстрым контрольным списком.
Я сделал эти маленькие 2 функции, которые хорошо работают с обнаружением / конверсией UTF-8 и ISO-8859-1 …
function detect_encoding($string) { //http://w3.org/International/questions/qa-forms-utf-8.html if (preg_match('%^(?: [\x09\x0A\x0D\x20-\x7E] | [\xC2-\xDF][\x80-\xBF] | \xE0[\xA0-\xBF][\x80-\xBF] | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} | \xED[\x80-\x9F][\x80-\xBF] | \xF0[\x90-\xBF][\x80-\xBF]{2} | [\xF1-\xF3][\x80-\xBF]{3} | \xF4[\x80-\x8F][\x80-\xBF]{2} )*$%xs', $string)) return 'UTF-8'; //If you need to distinguish between UTF-8 and ISO-8859-1 encoding, list UTF-8 first in your encoding_list. //if you list ISO-8859-1 first, mb_detect_encoding() will always return ISO-8859-1. return mb_detect_encoding($string, array('UTF-8', 'ASCII', 'ISO-8859-1', 'JIS', 'EUC-JP', 'SJIS')); } function convert_encoding($string, $to_encoding, $from_encoding = '') { if ($from_encoding == '') $from_encoding = detect_encoding($string); if ($from_encoding == $to_encoding) return $string; return mb_convert_encoding($string, $to_encoding, $from_encoding); }
Если ваша база данных содержит строки в двух разных кодировках, то я бы сделал это вместо того, чтобы преследовать весь ваш код приложения с помощью обнаружения / преобразования charset, чтобы написать сценарий «один выстрел», который будет читать все ваши записи в таблицах и обновлять их строки до правильного (я бы выбрал UTF-8, если бы я был вами). Таким образом, ваш код будет чище и проще в обслуживании.
Просто записывайте записи циклов в каждую таблицу вашей базы данных и конвертируйте строки следующим образом:
//if the 3rd param is not specified the "from encoding" is detected automatically $newString = convert_encoding($oldString, 'UTF-8');