Где я ошибся с этим полем Unicode в MySQL? - PullRequest
2 голосов
/ 07 августа 2009

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

Версия MySQL - 5.0.51a. Набор символов по умолчанию для таблицы - utf8.

Многие строки имеют символы Юникода, такие как \ xae и \ u21222 (зарегистрированный символ и символ товарного знака соответственно).

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

"Bing® Blang™ Blaow"

Набор символов по умолчанию для моего клиента командной строки mysql - "latin1".

Если я выполню оператор SELECT в клиентской программе mysql из командной строки без указания набора символов, вывод заголовка будет выглядеть следующим образом:

"Bing® Blang Blaow"

Символ (R) правильный, но символ (TM) отсутствует. Если я вырежу и вставлю эту строку из консоли в TextMate, появится символ (TM), но он будет на полпути от g в слове «Blang».

Я полагаю, что функция "наполовину позади" - это просто ошибка отображения в TextMate (хотя, если кто-то и может предоставить дополнительную информацию, это было бы здорово, но это не очень важная часть).

Главное, что я могу сделать вывод из поведения «там-после-после-вырезать-вставить», заключается в том, что данные находятся в базе данных, но что-то не так с каким-то набором символов где-то.

Если я переопределяю кодировку клиента mysql по умолчанию в командной строке, то вот так:

mysql --default-character-set=utf8 

Затем сделайте тот же выбор, строка выглядит так:

"Bing® Blang™ Blaow"

, что означает, что оба символа (R) и (TM) появляются и находятся в нужном месте, но им предшествует символ Unicode \ xae, который представляет собой букву A с огибающей сверху.

(Кстати, это также, как данные отображаются, когда я вынимаю их с помощью python и отображаю их на веб-странице, что является моей реальной проблемой).

В любом случае, что здесь происходит? Все, что мы сделали в последнее время, использовало UTF8 везде, где только возможно, но возможно, что некоторые из этих строк были вставлены до этого изменения, что означает, что они использовали бы значение по умолчанию для latin1 ... однако ни одна из кодировок не дает правильного результата?

Если строки были вставлены, когда кодировка по умолчанию для таблицы была latin1, прежде чем она была переключена на utf8, то кодировка была переключена (через alter table ..), тогда будет ли кодировка фактически обновлена? Должна ли одна из кодировок работать сейчас? Юникод когда-нибудь перестанет пинать мою задницу?

Ответы [ 4 ]

2 голосов
/ 10 августа 2009

Здесь довольно много вопросов:

О символах

Вы указываете, что текст содержит символы U + AE и U + 2122 (® и ™ соответственно). Тем не менее, результаты означают, что текст имеет символ U + 99 в качестве символа после «Бланга»: Когда вы устанавливаете MySQL для вывода UTF8, вы видите это «Â ™» - то есть последовательность UTF8 для U + 99, отображаемую на терминал, который интерпретирует этот поток байтов как Windows-1252.

U + 99, вероятно, не то, что вы хотели: в Unicode это расширенный управляющий символ без графического представления. Так получилось, что в Windows-1252 код 0x99 является символом товарного знака (U + 2122).

(Обратите внимание, что как для MySQL, так и для большинства веб-браузеров характерно «разбитое» поведение при использовании Windows-1252 при выборе Latin1. Вздох.)

Что, вероятно, не так

  1. Ваш терминал не работает с правильным набором символов. Он явно работает в Windows-1252.

  2. Программы должны подключаться к базе данных в UTF-8. Вы можете сделать это в командной строке, как вы нашли, или выполнив оператор SET NAMES utf8_general_ci; в дескрипторе базы данных, прежде чем делать что-либо еще. У некоторых других API баз данных могут быть другие способы сделать это, но нет общего способа для всех механизмов SQL. SET NAMES ... относится к MySQL, но устанавливает все необходимые переменные набора символов (их три!) Одновременно.

  3. Процесс вставки данных в базу данных принимает пользовательский ввод и неправильно преобразовывает его из Windows-1252 в UTF-8 перед вставкой. Вот как вы получили U + 99 в вашу базу данных. Поскольку я не знаю, как вы получаете эти данные, я не уверен, что исправить, но здесь есть несколько возможностей:

    1. Если данные поступают из формы веб-страницы, убедитесь, что страница с формой обслуживается в UTF-8, должным образом помечена как таковая (через MIME-тип и тег <meta>). Также убедитесь, что тег <form> не указывает другой набор символов.

    2. При преобразовании данных убедитесь, что вы используете iconv или аналогичные библиотеки для преобразования из набора символов ввода в UTF-8. Даже если вы думаете, что ввод латиницы 1, не пытайтесь делать это вручную (например, путем расширения нуля каждого байта до 16 бит, а затем утверждая, что это UTF-16 - это не сработает для Windwos-1252!). Убедитесь, что вы знаете набор символов исходных данных. В частности, обязательно узнайте, является ли это Latin1 или Windows-1252.

    3. Вместо преобразования пользовательского ввода вы можете подключиться к базе данных в наборе символов пользовательского ввода, а затем просто вставить необработанные байтовые данные, полученные от пользователя. Однако вы должны быть уверены, что вставки выполняются только таким образом: чтение данных из данных с действующим набором символов пользователя приведет к потере информации, если в других строках есть данные, которые не могут быть представлены в этом наборе символов. Можно установить соединение MySQL так, чтобы вы выполняли операторы в одном наборе символов и читали результаты обратно в другом ... Но это не для слабонервных, и будущие программисты, вероятно, сойдут с ума, пытаясь понять, почему код делает это.

  4. Если, когда вы извлекаете данные с помощью Python и отображаете их на веб-странице, вы видите строку «Â ™», то это означает, что вы правильно извлекаете данные из базы данных как UTF. -8, но затем помещаем его на веб-страницу, которая неправильно идентифицируется как UTF-8. Вероятно, это просто по умолчанию Latin1, который, как отмечалось выше, действительно будет Windows-1252.

  5. Тем не менее, даже если вы исправите дисплей, обратите внимание, что в базе данных содержатся неверные данные, поскольку U + 99 на самом деле не является символом товарного знака в столбце UTF-8. Вам нужно будет очистить данные, прочитав все данные и заменив любые символы в диапазоне от U + 80 до U + 9F тем, что они, вероятно, должны были быть, при условии, что данные действительно были Windows-1252. Если вы не уверены, в каком наборе символов изначально были данные - тогда эти данные, увы, просто мусор.

Об изменении наборов символов таблиц

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

  2. Будьте внимательны, чтобы заметить разницу между ALTER TABLE foo CONVERT TO CHARACTER SET ... и ALTER TABLE foo CHARACTER SET ... Позднее только изменит набор символов по умолчанию для таблицы и не изменит никаких столбцов, даже если они были установлены по умолчанию при создании. (MySQL использует значения по умолчанию во время создания столбца, он не помнит, что данный столбец является «дефолтом» и не синхронизирует его с таблицей по умолчанию.)

1 голос
/ 07 августа 2009

Может ли быть так, что некоторые столбцы имеют явно другой набор символов, чем таблица по умолчанию?

1 голос
/ 10 августа 2009

как то так ...?

ALTER TABLE tbl_name Преобразование в набор символов UTF8 COLLATE utf8_general_ci

1 голос
/ 07 августа 2009

Я думаю, что это связано с настройками подключения mysql в вашем коде Python. попробуйте установить conn.character_set_name или что-то в этом роде, в зависимости от используемой библиотеки подключений mysql.

в случае MySQLdb это должно быть что-то вроде этого:

def character_set_name(*args, **kwargs): return 'utf-8'
conn.character_set_name = new.instancemethod(character_set_name, conn, conn.__class__)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...