Строки UTF-8 в базе данных MySQL испортились после изменения конфигурации - PullRequest
4 голосов
/ 22 октября 2011

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

База данных была заполнена PHP-скриптом. Все должно было быть в UTF-8, вот что настроено для базы данных.

Однако вот так выглядит строка:

fête

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

Теперь похоже, что это просто дважды перекодируется, но это не так. Эти четыре символа в шестнадцатеричном формате:

C3 83 C6 92 C3 82 C2 AA

Это очень похоже на UTF-8, поэтому, если мы расшифруем его, мы получим

C3 3F C2 AA

Это не совсем UTF-8 (из-за 3F), но давайте расшифруем его снова:

FF AA

Это не UTF-8.

Символ ê - это EA, в UTF-8 это будет C3 AA.

Другой пример. Испанский перевернутый вопросительный знак (¿) обозначен как C8 83 E2 80 9A C3 82 C2, который декодируется в C3 3F 82 BF, что опять не соответствует UTF-8 (переводится в FF 82 BF). Ожидаемый символ для ¿ равен BF, т.е. C2 BF в соответствующем UTF-8.

Что здесь произошло? Как персонажи запутались? Что еще более важно, как я могу это исправить?

(Примечание: новый сервер требует от меня записи mysql_set_charset("utf8");, иначе строки тоже будут испорчены, хотя и в стиле "UTF-8 as latin1", а не так странно, как показано выше.)

TL; ДР: * +1051 *

  • База данных MySQL была заполнена в UTF-8 через скрипт PHP
  • В течение нескольких лет простаивал, сервер был перенесен.
  • Теперь символы перепутаны, см. Выше.

Ответы [ 2 ]

8 голосов
/ 22 октября 2011
C3 83 C6 92 C3 82 C2 AA

Это очень похоже на UTF-8, поэтому, если мы расшифруем его, мы получим

C3 3F C2 AA

Это то, что вы получите, если обработать последовательность байтов какUTF-8, затем закодируйте его как ISO-8859-1.3F - это ?, который был включен в качестве символа замены, потому что UTF-8 C6 92 - это U + 0192 ƒ, которого нет в ISO-8859-1.Но она существует в кодексе Windows 1252 для Западной Европы, кодировка, очень похожая на ISO-8859-1;там это байт 0x83.

C3 83 C2 AA

Пройдите еще один раунд обработки-как-UTF-8-байтов-и-закодируйте в cp1252, и вы получите:

C3 AA

наконец, UTF-8 для ê.

Обратите внимание, что даже если вы явно обслуживаете HTML-страницу, отличную от XML, как ISO-8859-1, браузеры фактически используют кодировку cp1252 из-за неприятногоисторические причины.

К сожалению, MySQL не имеет кодировки cp1252;latin1 - это (правильно) ISO-8859-1.Таким образом, вы не сможете исправить данные, сбросив их как latin1, а затем перезагрузив как utf8 (дважды).Вам придется обработать скрипт с помощью текстового редактора, который можно сохранить как (или, например, в Python file(path, 'rb').read().decode('utf-8').encode('cp1252').decode('utf-8').encode('cp1252')).

1 голос
/ 22 октября 2011

Я подозреваю, что ваши символы могут храниться в виде строк UTF8 в базе данных latin1 (или аналогичной).Вот почему у вас проблема с «двойным кодированием».Создание базы данных CHARSET UTF8 должно исправить это.Дамп / импорт данных также может быть необходим, что-то вроде этого:

$ mysqldump --default-character-set=latin1  --skip-set-charset --databases xxx > xxx.sql
$ mysql --default-character-set=utf8 < xxx.sql

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

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