UTF8 Проблема кодирования - с хорошими примерами - PullRequest
23 голосов
/ 04 ноября 2010

У меня следующая проблема кодировки символов, каким-то образом мне удалось сохранить данные с другой кодировкой символов в моей базе данных (UTF8). Приведенный ниже код и выходные данные показывают 2 образца строк и их вывод.Один из них должен быть изменен на 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

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

ОБНОВЛЕНИЕ:

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

Ответы [ 6 ]

26 голосов
/ 04 ноября 2010

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

?>

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

9 голосов
/ 15 марта 2012

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

Encoding :: 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
6 голосов
/ 04 ноября 2010

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

echo (strlen($str)!==strlen(utf8_decode($str)))
  ? $str                //is multibyte, leave as is
  : utf8_encode($str);  //encode

Сравнивает длину исходной строки и строки utf8_decoded.Строка, содержащая многобайтовый символ, имеет strlen, который отличается от аналогичного strlen с однобайтовым кодированием.

Например:

strlen('Télécom') 

должно возвращать 7 в Latin1 и 9 в UTF8

1 голос
/ 04 ноября 2010

Я сделал эти две маленькие функции, которые хорошо работают с обнаружением / преобразованием 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);
}

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

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

//if the 3rd param is not specified the "from encoding" is detected automatically
$newString = convert_encoding($oldString, 'UTF-8');
0 голосов
/ 04 ноября 2010

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

SET NAMES UTF8;

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

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

  • Все файлы должны быть сохранены как UTF-8 (желательно без BOM [Маска байтового порядка])
  • Ваш HTTP-сервер должен отправить заголовок кодировки UTF-8,Используйте Firebug или Live HTTP Headers для проверки.
  • Если ваш сервер сжимает и / или маркирует ответ, вы можете увидеть содержимое заголовка в виде чанков или gzipped.Это не проблема, если вы сохраняете свои файлы как UTF-8 и
  • Объявите кодировку в заголовок HTML, используя правильный метатег.
  • Для всего приложения (сокеты, файловая система, базы данных ...) не забывает отмечать UTF-8 каждый раз, когда вы можете.Делая это при открытии соединения с базой данных или около того, вам не нужно постоянно кодировать / декодировать / отлаживать.Захватите их за корень.
0 голосов
/ 04 ноября 2010
  1. Какую базу данных вы используете?
  2. Вам нужно знать кодировку исходной строки перед тем, как преобразовать ее в utf-8, если она в ISO-8859-1 (latin1), тогда utf8_encode () - самый простой способ, в противном случае вам нужно использовать либо icov, либо mbstring lib для преобразования, и оба они должны знать кодировку ввода для правильного преобразования.
  3. Сообщаете ли вы своей базе данных о наборе символов при вставке / выборе данных?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...