这是我对错误消息的尝试。我究竟做错了什么?
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生成字节序列( ),并用于从字节序列( )中获取文本字符串 ( )。strunicodedecodeunicodestr
例如:
>>> 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")