Подтвердить что ты не робот

Проблема кодирования UTF8 - с хорошими примерами

У меня есть следующая проблема с кодировкой символов, так как мне удалось сохранить данные с различной кодировкой символов в моей базе данных (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 />";
?>

Выход 1:

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

Выход 2: ###

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

Спасибо за ваше время на этом. Кодировка символов, и я не очень хорошо себя чувствую!

UPDATE:

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
4b9b3361

Ответ 1

Это может быть задача для функции 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 />";

?>

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

Ответ 2

Я создал функцию, которая устраняет все эти проблемы. Он называется 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

Ответ 3

Другой способ, возможно, быстрее и менее ненадежный:

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

Ответ 4

Я не пробовал ваши образцы здесь, но из прошлого опыта, есть быстрое решение для этого. Сразу после подключения к базе данных выполните следующий запрос ПЕРЕД выполнением любых других запросов:

SET NAMES UTF8;

Это совместимый с SQL Standard и хорошо работает с другими базами данных, такими как Firebird и PostgreSQL.

Но помните, что вам нужно также обеспечить декларации UTF-8 в других местах, чтобы ваше приложение отлично работало. Следуйте за быстрым контрольным списком.

  • Все файлы должны быть сохранены как UTF-8 (желательно без спецификации [Маска байтового байта])
  • Ваш HTTP-сервер должен отправить заголовок кодировки UTF-8. Используйте Firebug или Live HTTP Headers для проверки.
  • Если ваш сервер сжимает и/или выполняет токенизацию ответа, вы можете увидеть содержимое заголовка как chunked или gzipped. Это не проблема, если вы сохраняете свои файлы как UTF-8 и
  • Объявить кодировку в заголовке HTML, используя правильный метатег.
  • Во всех приложениях (сокетах, файловой системе, базах данных...) не забывайте каждый раз указывать UTF-8. Выполняя это при открытии соединения с базой данных или, таким образом, вам не нужно постоянно кодировать/декодировать/отлаживать. Grab'em от root.

Ответ 5

Я сделал эти маленькие 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);
}

Если ваша база данных содержит строки в двух разных кодировках, что бы я сделал, вместо того, чтобы преследовать весь ваш код приложения с обнаружением/преобразованием набора символов, это написать "один выстрел" script, который будет читать все ваши записи и обновления таблиц их строки в правильном формате (я бы выбрал UTF-8, если бы я был вами). Таким образом, ваш код будет более чистым и простым в обслуживании.

Просто записывайте записи цикла в каждую таблицу вашей базы данных и преобразуйте строки следующим образом:

//if the 3rd param is not specified the "from encoding" is detected automatically
$newString = convert_encoding($oldString, 'UTF-8');

Ответ 6

  • В какой базе данных вы используете?
  • Вам нужно знать кодировку исходной строки, прежде чем преобразовать ее в utf-8, если это в ISO-8859-1 (latin1), то utf8_encode() является самым простым способом, иначе вам нужно использовать либо icov, либо mbstring lib для конвертирования, и оба из них должны знать кодировку ввода для правильного скрытия.
  • Сообщаете ли вы свою базу данных о кодировке при вставке/выборе данных?