Python编码 - 无法解码为utf8

6 投票
2 回答
17789 浏览
提问于 2025-04-18 05:37

我有一个sqlite数据库,它是由一个外部程序填充的。我想用python读取里面的数据,但每次尝试读取时都会出现一个错误:

操作错误:无法解码为UTF-8

如果我用sqlite管理工具打开数据库,查看那些出问题的记录,数据看起来没问题。但是当我把表导出为csv格式时,我发现那些出问题的记录里的字符£变成了£

当我在python中读取这个csv文件时,那些出问题的记录里的£依然显示为£,不过这对我来说没关系,我可以手动处理。但是我希望能直接从数据库中读取数据,而不需要先转换成csv。

我在网上查了一些类似问题的答案,目前我尝试过把“text_factory”设置为“str”,还尝试过用sqlite管理工具把列的数据类型从TEXT改为BLOB,但还是出现这个错误。

我下面的代码运行后也出现了操作错误:无法解码为UTF-8

conn = sqlite3.connect('test.db')
conn.text_factory = str
curr = conn.cursor()
curr.execute('''SELECT xml_dump FROM hands_1 LIMIT  5000  , 5001''')
row = curr.fetchone()

数据库中所有超过5000的记录都有这个字符问题,因此会产生错误。

任何帮助都非常感谢。

2 个回答

6

如果数据库里的文本大部分是用UTF-8编码的,但你还是遇到了这个错误(无法解码为UTF-8),那么问题可能出在某些行的数据不合法,不符合UTF-8的标准。默认情况下,Python的decode()函数在遇到这种文本时会抛出一个异常。如果你碰到这种情况,想要简单地忽略这些错误,可以像下面这样设置一个text_factory

conn = sqlite3.connect('my-database.db')
conn.text_factory = lambda b: b.decode(errors = 'ignore')
25

Python试图通过将存储在数据库中的字节文本转换成python的str对象来帮助你。为了完成这个转换,Python需要猜测你查询返回的每个字节(或字节组)代表哪个字母。默认情况下,它使用一种叫做utf-8的编码来进行猜测。显然,在你的情况下,这个猜测是错误的。

解决办法是给Python一点提示,告诉它如何将字节映射到字母(也就是unicode字符)。你已经接近这个解决方案,使用了以下代码:

conn.text_factory = str

不过(根据你在上面评论中的回复),因为你使用的是Python 3,str是默认的文本工厂,所以那行代码对你来说不会有什么新效果(可以查看文档)。

这行代码背后发生的事情是,Python尝试使用str函数将查询返回的字节转换成字符串,类似于:

your_string = str(the_bytes, 'utf-8') # actually uses `conn.text_factory`, not `str`

...但是你想要的是一种不同的编码,替换掉'utf-8'。由于你不能改变str函数的默认编码,你需要用其他方式来模拟这个过程。你可以使用一个一次性的不带名字的函数,叫做lambda,来实现:

conn.text_factory = lambda x: str(x, 'latin1')

现在,当数据库将字节传递给Python时,Python会尝试使用'latin1'编码来将它们映射为字母,而不是使用'utf-8'编码。当然,我不知道'latin1'是否是你数据的正确编码。实际上,你可能需要尝试几种编码来找到合适的。我建议你先试试以下几种:

  • 'iso-8859-1'
  • 'utf-16'
  • 'utf-32'
  • 'latin1'

你可以在这里找到更完整的编码列表。

另一种选择是让从数据库中出来的字节保持字节格式。是否这样做对你有好处,取决于你的应用场景。你可以通过设置:

conn.text_factory = bytes

撰写回答