Python:为unicode消毒一个字符串?

问题描述:

可能重复:
Python UnicodeDecodeError - Am I misunderstanding encode?Python:为unicode消毒一个字符串?

我有我试图做的unicode()功能安全的字符串:

>>> s = " foo “bar bar ” weasel" 
>>> s.encode('utf-8', 'ignore') 

Traceback (most recent call last): 
    File "<pyshell#8>", line 1, in <module> 
    s.encode('utf-8', 'ignore') 
UnicodeDecodeError: 'ascii' codec can't decode byte 0x93 in position 5: ordinal not in range(128) 
>>> unicode(s) 

Traceback (most recent call last): 
    File "<pyshell#9>", line 1, in <module> 
    unicode(s) 
UnicodeDecodeError: 'ascii' codec can't decode byte 0x93 in position 5: ordinal not in range(128) 

我主要围绕挥舞这里。我需要做些什么来从字符串中删除不安全的字符?

与此question有点相关,虽然我无法解决它的问题。

这也将失败:

>>> s 
' foo \x93bar bar \x94 weasel' 
>>> s.decode('utf-8') 

Traceback (most recent call last): 
    File "<pyshell#13>", line 1, in <module> 
    s.decode('utf-8') 
    File "C:\Python25\254\lib\encodings\utf_8.py", line 16, in decode 
    return codecs.utf_8_decode(input, errors, True) 
UnicodeDecodeError: 'utf8' codec can't decode byte 0x93 in position 5: unexpected code byte 
+0

我想知道为什么'str'有一个'encode'函数,并且“encoding”参数是指定结果的编码还是输入的编码。你究竟在这里试图做什么? – Thanatos 2010-07-11 20:01:43

+0

请检查[this](http://*.com/questions/368805/python-unicodedecodeerror-am-i-mis-understanding-encode/370199#370199)回答相关问题:“Python UnicodeDecodeError - 我误解了编码? “ – tzot 2010-07-11 22:37:08

+0

对于那些寻求解决方案来清理unicode特殊字符到(X)HTML中,请尝试'u'my unicode str'.encode'('ascii','xmlcharrefreplace')'。 – toszter 2014-02-13 20:23:07

编辑。看起来您的字符串编码方式为(左侧双引号)变为\x93(右侧双引号)变为\x94。有许多这样的映射代码页,CP1250就是其中之一,所以你可以使用这个:

s = s.decode('cp1250') 

对于所有这些映射\x93看到here(所有这些也映射\x94代码页,这可以验证here)。

+0

这个调用失败了(参见上面) – 2010-07-11 21:10:49

+0

@Rosarch OK,现在我看到原始字符串了。我已经更新了答案(同时@darkporter提出了相同的解决方案)。 – Bolo 2010-07-11 22:13:19

+0

代码页上的不错链接。看起来他们都是“窗户”上的变体。如果你是“西方人”,我会说坚持1252. – jpsimons 2010-07-11 22:23:05

好问题。编码问题很棘手。我们从开始“我有一个字符串。” Python 2中的字符串并不是真正的“字符串”,它们是字节数组。所以你的字符串,它从哪里来,它是什么编码?你的例子在文字中显示了引号,我甚至不知道你是如何做到的。我尝试将它粘贴到一个Python解释器中,或者在OS X上用Option-键入它,并且它不通过。

虽然看了你的第二个例子,但你有一个十六进制数为93的字符。不能是UTF-8,因为在UTF-8中,高于127的任何字节都是多字节序列的一部分。所以我猜它应该是Latin-1。问题是,x93不是Latin-1字符集中的字符。 Latin-1中的这个“无效”范围从x7f到x9f被认为是非法的。但是,微软看到了这个未使用的范围,并决定在那里放置“卷烟报价”。在这样做的时候,他们创建了一个名为“windows-1252”的相似编码,就像拉丁文-1,其中的东西在无效范围内。

因此,我们假设它是windows-1252。现在怎么办? String.decode将字节转换为Unicode,所以这就是你想要的。你的第二个例子是在正确的轨道上,但它失败了,因为字符串不是UTF-8。请尝试:

>>> uni = 'foo \x93bar bar\x94 weasel'.decode("windows-1252") 
u'foo \u201cbar bar\u201d weasel' 
>>> print uni 
foo “bar bar” weasel 
>>> type(uni) 
<type 'unicode'> 

这是正确的,因为开卷报价是Unicode U + 201C。现在你已经有了Unicode,你可以用你选择的任何编码将它序列化为字节(如果你需要通过它传递的话),或者如果它保留在Python中,就把它保留为Unicode。如果要转换为UTF-8,请使用对立函数string.encode。

>>> uni.encode("utf-8") 
'foo \xe2\x80\x9cbar bar \xe2\x80\x9d weasel' 

卷曲引号需要3个字节才能以UTF-8编码。你可以使用UTF-16,它们只有两个字节。尽管如此,你不能编码为ASCII或Latin-1,因为它们没有卷曲的引号。

+1

+1,但你也应该提到这个答案是特定于Python 2.x的。在3.x中,'str'类型被重命名为'bytes',而'unicode'被重命名为'str'。虽然起初令人困惑,但这种变化使得这种事情不太可能发生。 – 2010-07-11 22:42:07

+0

+1“让我们先从'我有一个字符串'”哈哈 – 2010-07-11 22:44:37

+1

@丹尼尔不要乱伦,但我只是投票了你的投票解释。确实如此:以上是Python 2.x特有的。 – jpsimons 2010-07-11 22:50:34