Подтвердить что ты не робот

Запись строки UTF-8 в MySQL с помощью Python

Я пытаюсь вывести данные учетной записи пользователя из 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

4b9b3361

Ответ 1

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

Ответ 2

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

Затем убедитесь, что вы передаете объекты юникода в ваше соединение db, поскольку оно будет кодировать его, используя кодировку, которую вы передали курсору. Если вы передаете строку, закодированную в 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

Ответ 3

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

UPDATE: Если я запустил следующее против тестовой таблицы, я получаю -

>>> 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 script, просто неправильно обрабатывает кодировку при выводе.

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

Ответ 4

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

Недавно у меня была такая же проблема, когда значение поля было байтовой строкой вместо 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 возвращается как строка байта вместо unicode. Однако он не является двоичным, MySQLdb.constants.FLAG.BINARY & cursor.description_flags[1] (флагов полей MySQLdb). Это похоже на ошибку в библиотеке (открыт # 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, можно добиться желаемого поведения декодирования в Юникоде.

Если вы хотите переопределить поведение здесь, как выглядит запись 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. Таким образом, вы также захотите преобразовать двоичные значения, вы можете поместить первый кортеж.

Ответ 6

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

Причина, по которой вы не получаете результаты 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 (да, это отстой, поскольку нет общее исправление).

Ответ 7

и db.set_character_set ('utf8'), следует, что use_unicode = Правда?

Ответ 8

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

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

это потому, что mysqlworkbench по умолчанию создает схему по latin1, поэтому сначала нужно установить кодировку! введите описание изображения здесь