Python:为unicode清理一个字符串?

Nic*_*ner 14 python unicode character-encoding

可能重复:
Python UnicodeDecodeError - 我是否误解编码?

我有一个字符串,我正在尝试为该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)
Run Code Online (Sandbox Code Playgroud)

我大部分时间都在这里挥舞着.如何从字符串中删除不安全的字符需要做什么?

与这个问题有点相关,虽然我无法从中解决我的问题.

这也失败了:

>>> 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
Run Code Online (Sandbox Code Playgroud)

jps*_*ons 39

好问题.编码问题很棘手.让我们从"我有一个字符串"开始吧.Python 2中的字符串不是真正的"字符串",它们是字节数组.所以你的字符串,它来自哪里,它是什么编码?您的示例在文字中显示了引号,我甚至不确定您是如何做到的.我尝试将其粘贴到Python解释器中,或者使用Option- [在OS X上键入它,但它没有通过.

看看你的第二个例子,你有一个十六进制93的字符.那不能是UTF-8,因为在UTF-8中,任何高于127的字节都是多字节序列的一部分.所以我猜它应该是Latin-1.问题是,x93不是Latin-1字符集中的字符.Latin-1中从x7f到x9f的这个"无效"范围被认为是非法的.但是,微软看到了未使用的范围,并决定在那里加上"曲线引号".在这样做的过程中,他们创建了一个名为"windows-1252"的类似编码,就像Latin-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'>
Run Code Online (Sandbox Code Playgroud)

这是正确的,因为打开卷曲引用是Unicode U + 201C.现在您已经拥有了Unicode,您可以使用您选择的任何编码将其序列化为字节(如果您需要通过网络传递它),或者如果它保留在Python中,则将其保留为Unicode.如果要转换为UTF-8,请使用反对函数string.encode.

>>> uni.encode("utf-8")
'foo \xe2\x80\x9cbar bar \xe2\x80\x9d weasel'
Run Code Online (Sandbox Code Playgroud)

卷曲引号需要3个字节才能以UTF-8编码.你可以使用UTF-16,它们只有两个字节.但是,您不能编码为ASCII或Latin-1,因为它们没有卷曲引号.


Bol*_*olo 5

编辑。看起来你的字符串的编码方式是\xe2\x80\x9c(左双引号) 变成\\x93(\xe2\x80\x9d右双引号) 变成\\x94。有许多具有此类映射的代码页,CP1250 就是其中之一,因此您可以使用以下代码:

\n\n
s = s.decode(\'cp1250\')\n
Run Code Online (Sandbox Code Playgroud)\n\n

对于映射\xe2\x80\x9c此处的所有代码页(所有代码页也映射到,可以在此处进行验证\\x93\xe2\x80\x9d\\x94进行验证)。

\n