Python字符串比较 - 特殊/Unicode字符的问题
我正在写一个Python脚本来处理一些音乐数据。这个脚本的目的是通过比较两个不同数据库中的条目,把它们合并在一起。现在几乎可以正常工作,但在比较包含特殊字符(比如带重音的字母)的字符串时出现了问题。我觉得这可能是ASCII和Unicode编码的问题,因为我收到了这样的错误信息:
“Unicode相等比较无法将两个参数转换为Unicode - 认为它们不相等”
我意识到我可以使用正则表达式来去掉那些麻烦的字符,但我处理的数据量很大,过多依赖正则表达式会让我的程序变得非常慢。有没有办法让Python正确比较这些字符串?到底发生了什么?有没有办法判断我的字符串是以ASCII还是Unicode存储的?
编辑1:我使用的是Python v2.6.6。在检查类型后,我发现一个数据库输出的是Unicode字符串,而另一个则是ASCII字符串。所以这可能就是问题所在。我试图用一行代码把第二个数据库的ASCII字符串转换成Unicode:
line = unicode(f.readline().decode(latin_1).encode(utf_8))
但这给了我一个这样的错误:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 41: ordinal not in range(128)
我不明白为什么‘ascii’编码会抱怨,因为我其实是想从ASCII解码。有人能帮忙吗?
4 个回答
把这两个都转换成unicode格式应该会有帮助:
if unicode(str1) == unicode(str2):
print "same"
你可能需要先处理一下数据库,把所有内容都转换成UTF-8格式。我猜你的某些数据里有拉丁-1编码的带重音符号的字符。
关于你的问题,想要确认唯一的方法就是查看一下。让你的脚本输出那些不匹配的内容,然后查一下它们的字符编码。或者你也可以试试 string.decode('latin1').encode('utf8')
,看看会发生什么。
Unicode与字节
首先,来了解一些基本概念。字符串有两种类型,编码和解码:
- 编码。这个是存储在硬盘上的内容。对Python来说,它就是一堆0和1,你可以把它当作ASCII,但其实可以是任何东西——二进制数据、JPEG图片等等。在Python 2.x中,这叫做“字符串”变量。在Python 3.x中,更准确地说,它叫做“字节”变量。
- 解码。这是实际的字符字符串。它们可以被编码成8位的ASCII字符串,也可以编码成32位的中文字符。但在转换成编码变量之前,它只是一个Unicode字符字符串。
这对你意味着什么
所以,事情是这样的。你说你得到了一个ASCII变量和一个Unicode变量。其实这并不准确。
- 你有一个变量是字节字符串——一堆0和1,假设是8个一组。这是你错误地认为是ASCII的变量。
- 你还有一个变量是Unicode数据——数字、字母和符号。
在你把字节字符串和Unicode字符字符串进行比较之前,你需要做一些假设。在你的情况下,Python(以及你)假设字节字符串是ASCII编码的。这在你遇到一个不是ASCII的字符时就出问题了——比如带有重音符号的字符。
所以你需要找出这个字节字符串是用什么编码的。它可能是latin1。如果是的话,你需要这样做:
if unicode_variable == string_variable.decode('latin1')
latin1基本上是ASCII加上一些扩展字符,比如Ç和Â。
如果你的数据是latin1编码的,那你只需要这样做。但如果你的字节字符串是用其他编码的,你就需要弄清楚是什么编码,然后传给decode()。
总之,除非你知道(或者做一些假设)关于你的输入数据的编码,否则没有简单的答案。
我会怎么做
试着在你的字节字符串上运行var.decode('latin1')。这样会给你一个Unicode变量。如果这样有效,而且数据看起来正确(也就是说,带重音符号的字符看起来正常),那就继续用这个。
哦,如果latin1解析不成功或者看起来不对,试试utf8——另一种常见的编码。