字符串编码和解码?

时间:2012-07-05 07:48:06

标签: python python-2.7

以下是我对错误消息的尝试。我做错了什么?

string.decode("ascii", "ignore")

UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 37: ordinal not in range(128)

string.encode('utf-8', "ignore")

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

4 个答案:

答案 0 :(得分:85)

您无法解码unicode,也无法对str进行编码。尝试做the other way around

答案 1 :(得分:61)

猜测原始问题中遗漏的所有内容,但是,假设Python 2.x,关键是要仔细阅读错误消息:特别是在您调用'编码'但消息说'解码'反之亦然,但也包括消息中包含的值的类型。

在第一个示例中,string的类型为unicode,并且您尝试对其进行解码,这是将字节字符串转换为 unicode的操作。 Python帮助尝试使用默认的' ascii'将unicode值转换为str。编码,但由于你的字符串包含一个非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)

答案 2 :(得分:27)

除了向后收取decodeencode之外,我认为这里的部分答案实际上是不使用ascii编码。它可能不是你想要的。

首先,将str视为纯文本文件。它只是一堆没有实际附加编码的字节。如何解释它取决于阅读它的任何代码片段。如果你不知道这段话正在讨论什么,那么在你再继续之前,请立即阅读Joel的The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets

当然,我们都知道造成的混乱。答案是,至少在内存中,对所有字符串都有标准编码。这就是unicode进来的地方。我无法确切地追踪Python内部使用的编码,但这并不重要。关键是你知道它是以某种方式解释的字节序列。所以你只需要考虑字符本身,而不是字节。

问题在于,在实践中,你遇到了两者。有些图书馆会为您提供str,有些图书馆会提供str。当然,无论何时流式传输一系列字节(例如从磁盘传输或从磁盘请求传输),这都是有意义的。所以你需要能够来回翻译。

输入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一个字节序列,然后我告诉它,&#34;给我这个unicode版本,因为这个字节序列在'utf-8'。&#34;它就像我问的那样,这些字节(a heart character)现在被视为一个整体,由它们的Unicode代码点表示。

让我们走另一条路:

>>> u = u"I'm a string! Really! \u2764"
>>> codecs.encode(u, 'utf-8')
"I'm a string! Really! \xe2\x9d\xa4"

我给Python一个Unicode字符串,我要求它使用'utf-8'编码将字符串转换为字节序列。所以它确实如此,现在心脏只是一堆字节,它不能打印成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'是两者中的section character 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尽最大努力通过更改名称来使这个非常更清晰。在Python 3中,str已替换为bytesunicode已替换为str

答案 3 :(得分:2)

这是因为您的输入字符串无法根据编码规则进行转换(默认情况下为strict)。

我不知道,但我总是使用直接使用unicode()构造函数进行编码,至少这是official documentation的方式:

unicode(your_str, errors="ignore")