У меня есть 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 как latin1» не в этом странном виде, как показано выше).
TL; DR:
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 Western European, кодировке, очень похожей на ISO-8859-1; там, это байт 0x83.
C3 83 C2 AA
Пройдите еще один раунд лечения-как-UTF-8-bytes-and-encode-to-cp1252, и вы получите:
C3 AA
который, наконец, UTF-8 для ê
.
Обратите внимание, что даже если вы используете HTML-страницу, отличную от XML, явно как ISO-8859-1, браузеры фактически будут использовать кодировку cp1252 из-за неприятных исторических причин.
К сожалению, у MySQL нет кодировки cp1252; latin1
(правильно) ISO-8859-1. Таким образом, вы не сможете исправить данные, сбросив как latin1, а затем перезагрузив как utf8 (дважды). Вам придется обработать скрипт текстовым редактором, который может быть сохранен как (или, например, в file(path, 'rb').read().decode('utf-8').encode('cp1252').decode('utf-8').encode('cp1252')
Python file(path, 'rb').read().decode('utf-8').encode('cp1252').decode('utf-8').encode('cp1252')
).
Я подозреваю, что ваши символы могут храниться как строки UTF8 в латинской (или подобной) базе данных. Вот почему у вас проблема с «двойным кодированием». Создание базы данных CHARSET UTF8 должно исправить ее. Может потребоваться также сброс / импорт данных, что-то вроде этого:
$ mysqldump --default-character-set=latin1 --skip-set-charset --databases xxx > xxx.sql $ mysql --default-character-set=utf8 < xxx.sql
Но это просто предложение, может работать, но не обязательно в вашем конкретном случае.