Python:使用重音字符比较字符串不起作用

时间:2014-08-13 16:29:51

标签: python string unicode encoding comparison

我对python很新。我试图从另一个列表中删除出现在一个列表中的文件。这些列表是通过在mac和windows上重定向ll -R来生成的(但是自从进行了一些处理 - 合并,排序等 - 使用其他python脚本)。 某些文件名具有重音和特殊符号。这些字符串,即使它们相同(打印相同,在包含列表的文件中看起来相同)也不相同。

我找到了关于如何在unicode中比较字符串和特殊字符的线程: Python String Comparison--Problems With Special/Unicode Characters 这与我的问题非常相似。我对编码以及如何更改字符串的编码做了一些阅读。 但是,我尝试了在编解码器文档中可以找到的所有编解码器: https://docs.python.org/2/library/codecs.html 对于所有可能的编解码器对,两个字符串不相等(参见下面的程序 - 尝试解码和编码选项)。

当我逐个查看两个字符串中的字符时,重音e在一个文件中显示为带重音的e(一个字符),在另一个文件中显示为两个字符(e和可打印为空格)。

任何想法都会受到赞赏。

我将两个文本文件缩小为一行一行(显然带有重音)。 我将文本文件上传到dropbox:testfilesindatatestmissingfiles(但尚未尝试从Dropbox下载新的副本)。

非常感谢!

PS。 很抱歉搞乱这些链接。我没有名声10 ......

#!/usr/bin/python3

import sys

codecs = [ 'ascii', 'big5', 'big5hkscs', 'cp037', 'cp424', 'cp437', 'cp500', 'cp720      ', 'cp737   ', 'cp775', 'cp850', 'cp852', 'cp855', 'cp856   ', 'cp857', 'cp858', 'cp860', 'cp861', 'cp862', 'cp863', 'cp864', 'cp865', 'cp866', 'cp869', 'cp874     ', 'cp875   ', 'cp932', 'cp949', 'cp950', 'cp1006   ', 'cp1026', 'cp1140', 'cp1250', 'cp1251', 'cp1252', 'cp1253', 'cp1254', 'cp1255', 'cp1256', 'cp1257', 'cp1258', 'euc_jp', 'euc_jis_2004', 'euc_jisx0213', 'euc_kr', 'gb2312', 'gbk', 'gb18030', 'hz', 'iso2022_jp', 'iso2022_jp_1', 'iso2022_jp_2', 'iso2022_jp_2004', 'iso2022_jp_3', 'iso2022_jp_ext', 'iso2022_kr', 'latin_1', 'iso8859_2', 'iso8859_3', 'iso8859_4', 'iso8859_5', 'iso8859_6', 'iso8859_7', 'iso8859_8', 'iso8859_9', 'iso8859_10', 'iso8859_13', 'iso8859_14', 'iso8859_15', 'iso8859_16', 'johab', 'koi8_r   ', 'koi8_u      ', 'mac_cyrillic', 'mac_greek', 'mac_iceland', 'mac_latin2', 'mac_roman', 'mac_turkish', 'ptcp154', 'shift_jis', 'shift_jis_2004', 'shift_jisx0213', 'utf_32', 'utf_32_be', 'utf_32_le', 'utf_16', 'utf_16_be', 'utf_16_le', 'utf_7', 'utf_8', 'utf_8_sig' ]

file1 = open('testmissingfiles','r')
file2 = open('testfilesindata','r')

list1 = file1.readlines()
list2 = file2.readlines()

word1 = list1[0].rstrip('\n')
word2 = list2[0].rstrip('\n')

for i in range(0,len(codecs)-1):
    for j in range(0,len(codecs)-1):
        try:
            encoded1 = word1.decode(codecs[i])
            encoded2 = word2.decode(codecs[j])

            if encoded1 == encoded2:
                sys.stdout.write('Succeeded with ' + codecs[i] + ' & ' + codecs[j] + '\n')
        except:
            pass

2 个答案:

答案 0 :(得分:4)

使用unicodedata.normalize将两个字符串规范化为相同的正常形式:

import unicodedata

encoded1 = unicodedata.normalize('NFC', word1.decode('utf8'))
encoded2 = unicodedata.normalize('NFC', word2.decode('utf8'))

答案 1 :(得分:2)

您的程序存在一些问题:

您的程序将在每个循环中生成一个AttributeError异常并因此生成password1word2都没有名为.decode()的方法。在Python3中,您可以字符串编码为字节序列,或者可以字节序列解码为字符串。

使用codecs是一个红鲱鱼。两个输入文件都是UTF-8编码的。当您从文件中读取文件时,文件中的字节会被成功解码。

您的字符串外观相似,但由不同的unicode代码点组成。具体地,“Adhésion”包括两个unicode代码点0065和0301,“LATIN SMALL LETTER E”和“COMBINING ACUTE ACCENT”。另一方面,第二个单词“Adhésion”包含单个代码点00E9,“LATIN SMALL LETTER E WITH ACUTE”。正如Daniel在他的回答中指出的那样,你可以通过首先对它们进行规范化来检查这些不同字符串的语义等价。

以下是我如何解决您的问题:

#!/usr/bin/python3

import sys
import unicodedata

with open('testmissingfiles', 'r') as fp:
    list1 = [line.strip() for line in fp]
with open('testfilesindata','r') as fp:
    list2 = [line.strip() for line in fp]

word1 = list1[0]
word2 = list2[0]

if word1 == word2:
    print("%s and %s are identical"%(word1, word2))
elif unicodedata.normalize('NFC', word1) == unicodedata.normalize('NFC', word2):
    print("%s and %s look the same, but use different code poitns"%(word1, word2))
else:
    print("%s and %s are unrelated"%(word1, word2))