用Python编写UTF-8string到MySQL
我正在尝试将用户帐户数据从Active Directory推送到我们的MySQL服务器。 这工作完美无瑕,但不知怎的,string最终显示了元音变音和其他特殊字符的编码版本。
Active Directory使用此示例格式返回一个string: M\xc3\xbcller
这实际上是Müller
的UTF-8编码,但我想将Müller
写入我的数据库而不是M\xc3\xbcller
。
我尝试使用此行转换string,但它导致在数据库中相同的string: tempEntry[1] = tempEntry[1].decode("utf-8")
如果我在python控制台中运行print "M\xc3\xbcller".decode("utf-8")
,输出是正确的。
有没有办法以正确的方式插入这个string? 我需要这种特定的格式为一个Web开发人员谁想要这个确切的格式,我不知道他为什么不能够直接使用PHP转换string。
其他信息:我正在使用MySQLdb; 表和列编码是utf8_general_ci
正如@ marr75所示,确保在连接上设置charset='utf8'
。 设置use_unicode=True
并不是严格必要的,因为它是通过设置字符集来暗示的。
然后确保你将unicode对象传递给你的数据库连接,因为它会使用你传递给游标的字符集进行编码。 如果你传递一个utf8编码的string,它会在到达数据库时进行双重编码。
所以,像这样的:
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分钟testing应该帮助你决定。
conn = MySQLdb.connect(charset='utf8', init_command='SET NAMES UTF8')
此外,这是4.1这么老,这是勉强值得一提的,确保你使用MySQL> = 4.1
假设你正在使用MySQLdb,你需要在创build连接时传递use_unicode = True和charset =“utf8”。
更新:如果我运行以下对testing表我得到 –
>>> 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脚本只是输出时不正确地处理编码。
正如Rob所指出的那样,use_unicode和charset组合在一起是关于连接的详细信息,但是我甚至对标准库之外最有用的python库有一种自然的偏见,所以我试图明确地说明如果库变化很容易发现错误。
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
我find了解决我的问题。 使用.decode('unicode_escape').encode('iso8859-1').decode('utf8')
解码string。 现在一切都按照它应该插入。 可以在这里find完整的其他解决scheme: 通过python-ldap使用来自Active Directory的unicode编码的string
最近我有同样的问题,字段值是一个字节string,而不是unicode。 这里有一点分析。
概观
一般来说,所有人都需要做一个游标的unicode值,是将charset
parameter passing给连接构造函数,并具有非二进制表字段(例如utf8_general_ci
)。 传递use_unicode
是无用的,因为只要charset
具有值,它就被设置为true。
MySQLdb尊重游标描述字段types,所以如果游标中有DATETIME
列,则这些值将被转换为Python datatime.datetime
实例, DECIMAL
转换为decimal.Decimal
等,但二进制值将按字节string表示。 大多数解码器是在MySQLdb.converters
中定义的,并且可以通过为连接构造函数提供conv
参数来在实例基础上覆盖它们。
但是,在这里unicode解码器是一个例外,这可能是一个devise缺陷。 它们直接附加到连接实例转换器的构造函数中。 所以只能在实例基础上覆盖它们。
解决方法
让我们看看问题代码。
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
字段是作为字节string而不是unicode返回的。 但它不是二进制的, MySQLdb.constants.FLAG.BINARY & cursor.description_flags[1]
( MySQLdb字段标志 )。 这看起来像在图书馆的错误(打开#90 )。 但它的原因,我看到MySQLdb.constants.FIELD_TYPE.LONG_BLOB
( cursor.description[1][1] == 251
, MySQLdb字段types )根本没有一个转换器。
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
字典,有可能实现所需的unicode解码行为。
如果你想重写这里的行为,可能的文本字段的字典条目看起来像是在构造函数之后。
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解码器将被应用。 所以你也想尝试转换二进制值,你可以popup第一个元组。
(想回答上面的答案,但没有足够的声誉…)
在这种情况下,你没有得到unicode结果的原因是:
>>> print c.fetchall() (('M\xc3\xbcller',),)
是使用* _bin归类的MySQLdb 1.2.x中的一个错误 ,请参阅:
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
在这种特殊的情况下(sorting规则utf8_bin – 或[任何] _bin …)你必须期待“原始”值,在这里UTF-8(是的,这很糟糕,因为没有通用的修复)。
和db.set_character_set('utf8'),暗示use_unicode = True?
还有另一种情况可能有点罕见。
如果你首先在mysqlworkbench中创build一个模式,你会得到编码错误,不能通过添加字符集configuration来解决它。
这是因为mysqlworkbench默认是通过latin1创build模式,所以你应该先设置字符集!