这是我对错误消息的尝试。我究竟做错了什么?
string.decode("ascii", "ignore")
UnicodeEncodeError:“ascii”编解码器无法在位置 37 编码字符 u'\xa0':序数不在范围内(128)
string.encode('utf-8', "ignore")
UnicodeDecodeError:“ascii”编解码器无法解码位置 37 中的字节 0xc2:序数不在范围内(128)
这是我对错误消息的尝试。我究竟做错了什么?
string.decode("ascii", "ignore")
UnicodeEncodeError:“ascii”编解码器无法在位置 37 编码字符 u'\xa0':序数不在范围内(128)
string.encode('utf-8', "ignore")
UnicodeDecodeError:“ascii”编解码器无法解码位置 37 中的字节 0xc2:序数不在范围内(128)
你不能解码 a unicode
,也不能编码 a str
。试着反过来做。
猜测原始问题中省略的所有内容,但是,假设 Python 2.x 关键是仔细阅读错误消息:特别是在您调用“编码”但消息显示“解码”的地方,反之亦然,而且消息中包含的值的类型。
在第一个示例string
中unicode
,您尝试对其进行解码,这是一个将字节字符串转换为unicode 的操作。Python 有用地尝试将 unicode 值转换为str
使用默认的“ascii”编码,但由于您的字符串包含非 ascii 字符,因此您收到错误消息,表明 Python 无法编码unicode值。这是一个显示输入字符串类型的示例:
>>> u"\xa0".decode("ascii", "ignore")
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
u"\xa0".decode("ascii", "ignore")
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 0: ordinal not in range(128)
在第二种情况下,您尝试对字节字符串进行反向编码。编码是将 unicode 转换为字节字符串的操作,因此 Python 会先尝试将字节字符串转换为 unicode,并且由于您没有给它一个 ascii 字符串,因此默认的 ascii 解码器会失败:
>>> "\xc2".encode("ascii", "ignore")
Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
"\xc2".encode("ascii", "ignore")
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 0: ordinal not in range(128)
除了获取decode
和encode
倒退之外,我认为这里的部分答案实际上是不使用ascii
编码。这可能不是你想要的。
首先,str
将您想象成一个纯文本文件。它只是一堆实际上没有附加编码的字节。它的解释方式取决于读取它的任何代码。如果您不知道这一段在说什么,请阅读 Joel 的《每个软件开发人员绝对、肯定必须了解 Unicode 和字符集的绝对最低要求》,然后再继续阅读。
自然,我们都知道造成的混乱。答案是,至少在内存中,对所有字符串都有一个标准编码。这就是unicode
进来的地方。我很难准确地跟踪 Python 内部使用的编码,但这并不重要。关键是您知道这是一个以某种方式解释的字节序列。所以你只需要考虑字符本身,而不是字节。
问题是,在实践中,你会同时遇到这两种情况。一些库给你一个str
,而一些期望一个str
. 当然,只要您正在流式传输一系列字节(例如到磁盘或从磁盘或通过 Web 请求),这都是有意义的。所以你需要能够来回翻译。
Enter codecs
:是这两种数据类型之间的翻译库。用于从文本字符串 ( )encode
生成字节序列( ),并用于从字节序列( )中获取文本字符串 ( )。str
unicode
decode
unicode
str
例如:
>>> s = "I look like a string, but I'm actually a sequence of bytes. \xe2\x9d\xa4"
>>> codecs.decode(s, 'utf-8')
u"I look like a string, but I'm actually a sequence of bytes. \u2764"
这里发生了什么?我给了 Python 一个字节序列,然后我告诉它,“给我这个的unicode
版本,因为这个字节序列在'utf-8'
.”中。它按照我的要求完成了,这些字节(一个心形字符)现在被视为一个整体,由它们的 Unicode 代码点表示。
让我们反过来:
>>> u = u"I'm a string! Really! \u2764"
>>> codecs.encode(u, 'utf-8')
"I'm a string! Really! \xe2\x9d\xa4"
'utf-8'
我给 Python 一个 Unicode 字符串,并要求它使用编码将字符串转换为字节序列。确实如此,现在心脏只是一堆无法打印为 ASCII 的字节;所以它向我显示了十六进制。
当然,我们也可以使用其他编码:
>>> s = "I have a section \xa7"
>>> codecs.decode(s, 'latin1')
u'I have a section \xa7'
>>> codecs.decode(s, 'latin1')[-1] == u'\u00A7'
True
>>> u = u"I have a section \u00a7"
>>> u
u'I have a section \xa7'
>>> codecs.encode(u, 'latin1')
'I have a section \xa7'
('\xa7'
是 Unicode 和 Latin-1 中的节字符。)
所以对于你的问题,你首先需要弄清楚你的编码str
是什么。
它来自一个文件吗?来自网络请求?从你的数据库?然后源确定编码。找出源的编码并使用它来将其翻译成unicode
.
s = [get from external source]
u = codecs.decode(s, 'utf-8') # Replace utf-8 with the actual input encoding
或者,也许你正试图在某个地方写出来。目的地期望什么编码?用它把它翻译成str
. UTF-8 是纯文本文档的不错选择;大多数东西都能读懂。
u = u'My string'
s = codecs.encode(u, 'utf-8') # Replace utf-8 with the actual output encoding
[Write s out somewhere]
您是否只是为了互操作性而在内存中来回翻译?然后只需选择一个编码并坚持下去;'utf-8'
可能是最好的选择:
u = u'My string'
s = codecs.encode(u, 'utf-8')
newu = codecs.decode(s, 'utf-8')
在现代编程中,您可能永远不想为此使用'ascii'
编码。它是所有可能字符的一个极小的子集,我所知道的任何系统都没有默认使用它或其他任何东西。
Python 3 does its best to make this immensely clearer simply by changing the names. In Python 3, str
was replaced with bytes
, and unicode
was replaced with str
.
那是因为你的输入字符串不能按照编码规则进行转换(默认是严格的)。
我不知道,但我总是直接使用 unicode() 构造函数进行编码,至少官方文档中是这样的:
unicode(your_str, errors="ignore")