Как исправить строки с двойным кодированием UTF-8, находящиеся в полях MySQL utf8_general_ci?

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

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

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

Обычно я настраивал небольшой PHP-патч script, зацикливая через затронутые таблицы, ВЫБОР записей, исправлял ошибочные записи, используя utf8_decode() в двойных кодированных полях и ОБНОВЛЯЯ их.

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

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

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

Любые другие решения/лучшие практики?

Ответы

Ответ 1

Измените таблицу, чтобы изменить набор символов столбца на латинский-1. Теперь у вас будут одиночные кодированные строки UTF-8, но они сидят в поле, чья сортировка должна быть латинской-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; поместите соответствующий тип столбца там, где ...)

Ответ 2

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

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

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

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

Ответ 3

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

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/

Ответ 4

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

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

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

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

Ответ 5

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

Ответ 6

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

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

Вы можете ВЫБРАТЬ ВХОДЬ, массируйте файл с помощью php или iconv, затем LOAD DATA INFILE.