Python字符串编码问题

2 投票
3 回答
2804 浏览
提问于 2025-04-17 11:56

我正在使用亚马逊的MWS API来获取我店铺的销售报告,然后把这个报告保存到数据库的一个表里。不过,当我试图把信息编码成Unicode格式时,遇到了编码错误。在查看报告(和亚马逊发给我的完全一样)时,我发现了这个字符串,它是买家的位置:

'S�o Paulo'

于是我尝试这样编码:

encodeme = 'S�o Paulo'
encodeme.encode('utf-8)

但是我得到了以下错误信息:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xef in position 1: ordinal not in range(128)

我之所以想要编码,是因为一旦Django看到这个字符,它就会发出警告并截断字符串,这样位置就只保存成了S,而不是:

São Paulo

任何帮助都非常感谢。

3 个回答

1

如果你还没去过,可以试试这个网页,看看能不能找到你想要的答案哦 ;)

这是官方的Python Unicode文档

4

我觉得你需要用正确的编码来解码,而不是把它编码成utf-8。试试

s = s.decode('utf-8')

不过,你需要知道该用哪种编码。输入的数据可能是其他编码,而不是utf-8。

你收到的错误 UnicodeDecodeError 意味着你的对象不是unicode,而是一个字节串。当你使用 bytestring.encode 时,字符串首先会用默认编码(ascii)解码成unicode对象,然后再用utf-8编码。

我来试着解释一下在python中 unicode stringutf-8 bytestring 的区别。

unicode 是python的一种数据类型,用来表示unicode字符串。在你的程序中,大多数字符串操作都用unicode。虽然python内部可能使用utf-8,也可能是utf-16,但这对你来说并不重要。

bytestring 是一种安全的二进制字符串,可以是任何编码。当你接收数据时,比如打开一个文件,你得到的是一个字节串,在大多数情况下,你会想把它解码成unicode。当你写入文件时,你需要把unicode对象编码成字节串。有时候,框架或库会为你处理解码/编码,但并不是总能做到,因为框架不一定知道该用哪种编码。

utf-8是一种编码,可以正确地把任何unicode字符串表示为字节串。不过,你不能用utf-8解码任何类型的字节串成unicode。你需要知道字节串使用了什么编码,才能进行解码。

4

看起来你遇到了一些编码问题。

首先,你需要确认亚马逊在发送给你的报告内容中使用的是什么编码。是UTF-8吗?还是ISO 8859-1?或者其他的编码?

不幸的是,亚马逊MWS报告API文档,特别是他们的API参考,并没有明确说明他们使用的编码。我看到他们提到的唯一编码是UTF-8,所以这应该是你首先考虑的。GetReport API文档(第36-37页)描述了响应元素Report的类型为xs:string,但我没有看到他们定义这个数据类型的地方。也许他们指的是XML Schema中的string数据类型

所以,我建议你把从亚马逊收到的报告内容的字节序列直接保存到一个文件中,不要进行任何转换。要注意,你调用AWS的代码可能会无意中修改报告内容的字符串。用二进制编辑器检查那个文件中的非ASCII字节。比如“São”这个词是以S\xC3\xA3o的形式存储,表示UTF-8编码吗?还是以S\xE3o的形式存储,表示ISO 8859-1编码?

我猜测你收到的报告是一个平面文件。亚马逊AWS的文档说你可以请求将报告以XML格式发送给你。这将有助于你获得一个明确的编码声明。

一旦你知道了报告内容的编码,你就需要正确处理它。你提到你在使用Django框架和Python语言代码来接收亚马逊AWS的报告。

有一点需要非常清楚(正如Skirmantas所解释的):

  • Unicode字符串包含字符。字节字符串包含字节(八位字节)。
  • 编码是将Unicode字符串转换为字节字符串。
  • 解码是将字节字符串转换为Unicode字符串。

你从亚马逊AWS获得的字符串是一个字节字符串。你需要解码它才能得到Unicode字符串。但是你的代码片段encodeme = 'São Paulo'给你的是一个字节字符串。encodeme.encode('utf-8')对字节字符串进行了编码,这不是你想要的。(缺少的结束引号也不太好。)

试试这个示例代码:

>>> reportbody = 'S\xc3\xa3o Paulo'   # UTF-8 encoded byte string
>>> reportbody.decode('utf-8')        # returns a Unicode string, u'...'
u'S\xe3o Paulo'

你可能会发现一些背景阅读很有帮助。我同意Hoxieboy的看法,你应该花时间阅读Python的Unicode HOWTO。同时也可以看看我需要了解Unicode的哪些知识?的高分回答。

撰写回答