使用Python将UTF-8字符串写入MySQL

Rap*_*tor 35 python unicode utf-8

我试图将用户帐户数据从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控制台中运行输出是正确的.

有没有办法以正确的方式插入这个字符串?对于想要拥有这种格式的Web开发人员,我需要这种特定的格式,我不知道他为什么不能直接使用PHP转换字符串.

附加信息:我正在使用MySQLdb; 表和列编码是utf8_general_ci

Rob*_*wie 50

正如@ marr75建议的那样,请确保设置charset='utf8'连接.设置use_unicode=True并非严格必要,因为设置字符集意味着设置.

然后确保将unicode对象传递给db连接,因为它将使用传递给游标的charset对其进行编码.如果您传递的是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,))
Run Code Online (Sandbox Code Playgroud)

您也可以通过传递init_command参数来尝试强制连接使用utf8,但我不确定这是否是必需的.5分钟的测试应该可以帮助您做出决定.

conn = MySQLdb.connect(charset='utf8', init_command='SET NAMES UTF8')
Run Code Online (Sandbox Code Playgroud)

此外,这几乎不值得一提,因为4.1已经过时了,请确保使用MySQL> = 4.1


mar*_*r75 18

假设您正在使用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',),)
Run Code Online (Sandbox Code Playgroud)

这是"正确的方式",正确存储和检索字符,编写php脚本的朋友在输出时没有正确处理编码.

正如Rob指出的那样,use_unicode和charset结合在一起是关于连接的冗长,但是我对标准库之外的最有用的python库有一个自然的偏执,所以我试图明确地让库变更容易找到bug .


Rap*_*tor 9

我找到了解决问题的方法.解码字符串.decode('unicode_escape').encode('iso8859-1').decode('utf8')最后确实有效.现在一切都按预期插入.完整的其他解决方案可以在这里找到:通过python-ldap从Active Directory处理unicode编码的字符串


YEH*_*YEH 9

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
Run Code Online (Sandbox Code Playgroud)


saa*_*aaj 5

最近我遇到了同样的问题,字段值是字节串而不是unicode.这是一个小分析.

概观

通常,所有人都需要从游标中获取unicode值,即将charset参数传递给连接构造函数并具有非二进制表字段(例如utf8_general_ci).传递use_unicode是无用的,因为只要charset有值,它就会设置为true .

MySQLdb的尊重光标描述字段类型,因此,如果有一个DATETIME在光标列中的值将被转换到Python datatime.datetime实例,DECIMALdecimal.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)
Run Code Online (Sandbox Code Playgroud)

它显示该b字段作为字节字符串而不是unicode返回.但它不是二进制的MySQLdb.constants.FLAG.BINARY & cursor.description_flags[1](MySQLdb字段标志).它似乎是库中的bug(打开#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)
Run Code Online (Sandbox Code Playgroud)

因此,通过操纵连接实例converterdict,可以实现期望的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>)]
Run Code Online (Sandbox Code Playgroud)

MySQLdb.constants.FLAG.BINARY == 128.这意味着如果一个字段有二进制标志,那么将str应用unicode解码器.所以你想尝试转换二进制值,你可以弹出第一个元组.