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)
我现在有点手忙脚乱。请问我需要怎么做才能把字符串中的不安全字符去掉呢?
这和这个问题有点关系,不过我没能从中找到解决我的问题的方法。
这个也不行:
>>> 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
2 个回答
这是个好问题。编码问题确实很复杂。我们先从“我有一个字符串。”开始说起。在Python 2中,字符串其实并不是真正的“字符串”,它们是字节数组。那么你的字符串是从哪里来的,它用的是什么编码呢?你给的例子里有弯引号,我甚至不太确定你是怎么做到的。我尝试把它粘贴到Python解释器里,或者在OS X上用Option-[输入,但都不行。
不过看你第二个例子,你有一个十六进制的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'>
这是正确的,因为开弯引号是Unicode U+201C。现在你有了Unicode,你可以把它序列化成任何你选择的编码(如果需要传输的话),或者如果只在Python内部使用,就保持Unicode。如果你想转换成UTF-8,使用相反的函数,string.encode。
>>> uni.encode("utf-8")
'foo \xe2\x80\x9cbar bar \xe2\x80\x9d weasel'
在UTF-8中,弯引号需要3个字节来编码。如果你用UTF-16,它们只需要两个字节。不过,你不能用ASCII或Latin-1来编码,因为它们没有弯引号。