Как исправить дважды кодированные строки UTF-8, сидящие в полях MySQL utf8_general_ci? - PullRequest
14 голосов
/ 10 мая 2011

Мне нужно изменить класс, в котором (помимо прочего) строки UTF-8 неправильно кодируются дважды:

$string = iconv('ISO-8859-1', 'UTF-8', $string);
:
$string = utf8_encode($string);

Эти ошибочные строки были сохранены в нескольких полях таблицы по всей базе данных MySQL.Все затронутые поля используют параметры сортировки utf8_general_ci.

. Обычно я устанавливаю небольшой сценарий исправления PHP, циклически проходя через затронутые таблицы, выбирая записи, исправляя ошибочные записи, используя utf8_decode() на двойномзакодированные поля и ОБНОВЛЕНИЕ их.

Поскольку на этот раз я получил много огромных таблиц, и ошибка затрагивает только умлауты Германии (äöüßÄÖÜ), мне интересно, есть ли решение умнее / быстрее этого.

Являются ли чистые решения MySQL, такие как следующие, безопасными и рекомендуемыми?

 UPDATE `table` SET `col` = REPLACE(`col`, 'ä', 'ä');

Какие-либо другие решения / лучшие практики?

Ответы [ 6 ]

20 голосов
/ 10 мая 2011

Измените таблицу, чтобы изменить набор символов столбца на Latin-1.Теперь у вас будут строки UTF-8 с одиночным кодированием, но вы сидите в поле, чье сопоставление должно быть Latin-1.

В таком случае измените набор символов столбца обратно на UTF-8 с помощьюдвоичный набор символов - таким образом MySQL не преобразует символы ни в какой точке.

ALTER TABLE MyTable MODIFY MyColumn ... CHARACTER SET latin1
ALTER TABLE MyTable MODIFY MyColumn ... CHARACTER SET binary
ALTER TABLE MyTable MODIFY MyColumn ... CHARACTER SET utf8

(правильный синтаксис iirc; поместите соответствующий тип столбца в где ...)

13 голосов
/ 02 декабря 2011

Я попробовал опубликованные решения, но моя БД продолжала выкладывать ошибки.В конце концов я наткнулся на следующее решение (на форуме я верю, но не могу вспомнить, где):

UPDATE table_name SET col_name = CONVERT(CONVERT(CONVERT(col_name USING latin1) USING binary) USING utf8);

, и это сработало.Надеюсь, что это поможет любому, кто споткнулся здесь из отчаянного поиска в Google, как я.

ПРИМЕЧАНИЕ. Это, конечно, предполагает, что проблемы с двойным кодированием происходят из-за очень полезного преобразования MySQL из latin1 в utf8, но я считаю, что именно здесьиз этих "испорченных персонажей" случается.Это в основном делает то же самое преобразование, как упомянуто выше, обратно в latin1, затем в двоичный файл, затем в utf8 (используя двоичный шаг как способ предотвратить перекодирование уже закодированных объектов latin1)

7 голосов
/ 01 февраля 2012

Я нашел следующий подход проще:

mysqldump -h DB_HOST -u DB_USER -p --skip-set-charset --default-character-set=latin1 DB_NAME > DB_NAME-dump.sql

Затем удалите все таблицы и выполните повторный импорт с помощью следующей команды:

mysql -h DB_HOST -u DB_USER -p --default-character-set=utf8 DB_NAME < DB_NAME-dump.sql

Подсказка была найдена по этому URL: http://blog.hno3.org/2010/04/22/fixing-double-encoded-utf-8-data-in-mysql/

1 голос
/ 10 мая 2011

MySql поддерживает кодировки, поэтому вы можете конвертировать в SQL. Но в этом случае я бы предпочел просто написать скрипт на PHP, так как в любом случае это одноразовая задача.

Имейте в виду, что столбцы в MySql имеют свойство charset. Сопоставление (в теории) ортогонально к кодировке. Хотя сопоставление utf8_general_ci будет означать , что кодировка utf8, это не дано. Теоретически вы можете смешать сопоставление utf8 с кодировкой latin1 (и в результате получить мусор).

Если вы решите сделать это в SQL, посмотрите здесь:

http://dev.mysql.com/doc/refman/5.0/en/charset-convert.html

0 голосов
/ 10 мая 2011

Создайте дамп с помощью mysqldump, измените объявление кодировки (это в первых командах) и перезагрузите в другую базу данных.

Вы также можете использовать iconv в своем дампе для его перекодирования.

Вы можете выбрать SELECT INUT OUTFILE, скопировать файл с помощью php или iconv, затем ЗАГРУЗИТЬ ИНФИЛЬ ДАННЫХ.

0 голосов
/ 10 мая 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...