Запись строки UTF-8 в MySQL с помощью Python - PullRequest
33 голосов
/ 01 июня 2011

Я пытаюсь отправить данные учетной записи пользователя из Active Directory на наш MySQL-сервер. Это работает безупречно, но каким-то образом строки в конечном итоге показывают закодированную версию умлаутов и других специальных символов.

Active Directory возвращает строку, используя этот пример формата: M\xc3\xbcller

На самом деле это кодировка UTF-8 для Müller, но я хочу записать Müller в мою базу данных, а не M\xc3\xbcller.

Я попытался преобразовать строку с этой строкой, но это приводит к той же строке в базе данных: tempEntry[1] = tempEntry[1].decode("utf-8")

Если я запускаю print "M\xc3\xbcller".decode("utf-8") в консоли python, вывод верен.

Есть ли способ правильно вставить эту строку? Мне нужен этот конкретный формат для веб-разработчика, который хочет иметь именно этот формат, я не знаю, почему он не может конвертировать строку с помощью PHP напрямую.

Дополнительная информация: я использую MySQLdb; Кодировка таблицы и столбца: utf8_general_ci

Ответы [ 8 ]

50 голосов
/ 01 июня 2011

Как подсказывает @ marr75, убедитесь, что вы установили charset='utf8' в своих соединениях.Установка use_unicode=True не обязательна строго , поскольку это подразумевается установкой кодировки.

Затем убедитесь, что вы передаете Unicode объекты в ваше соединение с БД, как это будетзакодируйте его, используя кодировку, переданную курсору.Если вы передаете строку в кодировке utf8, она будет закодирована дважды, когда достигнет базы данных.

Итак, что-то вроде:

conn = MySQLdb.connect(host="localhost", user='root', password='', db='', charset='utf8')
data_from_ldap = 'M\xc3\xbcller'
name = data_from_ldap.decode('utf8')
cursor = conn.cursor()
cursor.execute(u"INSERT INTO mytable SET name = %s", (name,))

Вы также можете попробовать принудительно использовать соединениеutf8, передавая параметр init_command, хотя я не уверен, требуется ли это.5-минутное тестирование должно помочь вам принять решение.

conn = MySQLdb.connect(charset='utf8', init_command='SET NAMES UTF8')

Кроме того, об этом едва ли стоит упоминать, поскольку 4.1 уже устарел, убедитесь, что вы используете MySQL> = 4.1

17 голосов
/ 01 июня 2011

Если вы используете MySQLdb, вам нужно передать use_unicode = True и charset = "utf8" при создании вашего соединения.

ОБНОВЛЕНИЕ: Если я запускаю следующее для тестовой таблицы, я получаю -

>>> db = MySQLdb.connect(host="localhost", user='root', passwd='passwd', db='sandbox', use_unicode=True, charset="utf8")
>>> c = db.cursor()
>>> c.execute("INSERT INTO last_names VALUES(%s)", (u'M\xfcller', ))
1L
>>> c.execute("SELECT * FROM last_names")
1L
>>> print c.fetchall()
(('M\xc3\xbcller',),)

Это «правильный путь», символы хранятся и извлекаются правильно, ваш друг, пишущий сценарий php, просто неправильно обрабатывает кодировку при выводе.

Как указывает Роб, объединенные use_unicode и charset являются многословными по поводу соединения, но у меня есть естественная паранойя даже относительно самых полезных библиотек python за пределами стандартной библиотеки, поэтому я стараюсь быть явным, чтобы упростить ошибкичтобы найти, изменится ли библиотека.

9 голосов
/ 05 августа 2011

Я нашел решение своих проблем.Декодирование строки с .decode('unicode_escape').encode('iso8859-1').decode('utf8') наконец сработало.Теперь все вставлено как надо.Полное другое решение можно найти здесь: Работа с Unicode-кодированными строками из Active Directory через python-ldap

8 голосов
/ 20 августа 2014
import MySQLdb

# connect to the database
db = MySQLdb.connect("****", "****", "****", "****") #don't use charset here

# setup a cursor object using cursor() method
cursor = db.cursor()

cursor.execute("SET NAMES utf8mb4;") #or utf8 or any other charset you want to handle

cursor.execute("SET CHARACTER SET utf8mb4;") #same as above

cursor.execute("SET character_set_connection=utf8mb4;") #same as above

# run a SQL question
cursor.execute("****")

#and make sure the MySQL settings are correct, data too
5 голосов
/ 28 ноября 2014

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

Обзор

В общем, все, что нужно для получения Unicode-значений от курсора, это передать аргумент charset конструктору соединений и иметь недвоичные поля таблицы(например, utf8_general_ci).Передача use_unicode бесполезна, поскольку она имеет значение true, когда charset имеет значение.

MySQLdb учитывает типы полей описания курсора, поэтому, если в курсоре есть столбец DATETIME, значения будут преобразованы вЭкземпляры Python datatime.datetime, DECIMAL до decimal.Decimal и т. Д., Но двоичные значения будут представлены как есть байтовыми строками.Большинство декодеров определены в MySQLdb.converters, и их можно переопределить на основе экземпляра, предоставив аргумент conv конструктору соединения.

Но декодеры Unicode здесь являются исключением, что, вероятно, является недостатком дизайна.Они добавляются непосредственно к конвертерам экземпляра соединения в его конструкторе.Таким образом, их можно переопределить только на instance-basic.

Обходной путь

Давайте посмотрим код ошибки.

import MySQLdb

connection = MySQLdb.connect(user = 'guest', db = 'test', charset = 'utf8')
cursor     = connection.cursor()

cursor.execute(u"SELECT 'abcdё' `s`, ExtractValue('<a>abcdё</a>', '/a') `b`")

print cursor.fetchone() 
# (u'abcd\u0451', 'abcd\xd1\x91')
print cursor.description 
# (('s', 253, 6, 15, 15, 31, 0), ('b', 251, 6, 50331648, 50331648, 31, 1))
print cursor.description_flags 
# (1, 0)

Это показывает, что поле b возвращается какстрока байтов вместо юникода.Однако это не двоичный файл, MySQLdb.constants.FLAG.BINARY & cursor.description_flags[1] ( MySQLdb field flags ).Похоже, ошибка в библиотеке (открыт # 90 ).Но причину этого я вижу как MySQLdb.constants.FIELD_TYPE.LONG_BLOB (cursor.description[1][1] == 251, типы полей MySQLdb ) просто не имеет преобразователя вообще.

import MySQLdb
import MySQLdb.converters as conv
import MySQLdb.constants as const

connection = MySQLdb.connect(user = 'guest', db = 'test', charset = 'utf8')
connection.converter[const.FIELD_TYPE.LONG_BLOB] = connection.converter[const.FIELD_TYPE.BLOB]
cursor = connection.cursor()

cursor.execute(u"SELECT 'abcdё' `s`, ExtractValue('<a>abcdё</a>', '/a') `b`")

print cursor.fetchone()
# (u'abcd\u0451', u'abcd\u0451')
print cursor.description
# (('s', 253, 6, 15, 15, 31, 0), ('b', 251, 6, 50331648, 50331648, 31, 1))
print cursor.description_flags
# (1, 0)

Таким образом, манипулируя экземпляром соединения converter dict, можно добиться желаемого поведения декодирования Unicode.

Если вы хотите переопределить поведение, вот как выглядит запись dict для возможного текстового поля после конструктора.

import MySQLdb
import MySQLdb.constants as const

connection = MySQLdb.connect(user = 'guest', db = 'test', charset = 'utf8')
print connection.converter[const.FIELD_TYPE.BLOB]
# [(128, <type 'str'>), (None, <function string_decoder at 0x7fa472dda488>)]

MySQLdb.constants.FLAG.BINARY == 128.Это означает, что если поле имеет двоичный флаг, оно будет str, в противном случае будет применен декодер Unicode.Таким образом, вы также хотите попытаться преобразовать двоичные значения, вы можете получить первый кортеж.

2 голосов
/ 13 августа 2012

(хотел бы ответить на вышеуказанный ответ, но у вас недостаточно репутации ...)

Причина, по которой вы не получаете Unicode-результаты в этом случае:

>>> print c.fetchall()
(('M\xc3\xbcller',),)

ошибка из MySQLdb 1.2.x с сопоставлением * _bin, см.

http://sourceforge.net/tracker/index.php?func=detail&aid=1693363&group_id=22307&atid=374932 http://sourceforge.net/tracker/index.php?func=detail&aid=2663436&group_id=22307&atid=374932

В данном конкретном случае (сопоставление utf8_bin - или [что угодно] _bin ...) вы должны ожидать «сырое» значение, здесь utf-8 (да, это отстой, так как нет общего исправления).

0 голосов
/ 03 апреля 2017

есть другая ситуация, может быть, немного редкая.

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

это потому, что mysqlworkbench по умолчанию создает схему по latin1, поэтому сначала вы должны установить charset!enter image description here

0 голосов
/ 11 октября 2011

и db.set_character_set ('utf8'), подразумевают, что use_unicode = True?

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