希望Python创build一个UTF-8文件,得到一个ANSI。 为什么?

我有以下function:

def storeTaggedCorpus(corpus, filename): corpusFile = codecs.open(filename, mode = 'w', encoding = 'utf-8') for token in corpus: tagged_token = '/'.join(str for str in token) tagged_token = tagged_token.decode('ISO-8859-1') tagged_token = tagged_token.encode('utf-8') corpusFile.write(tagged_token) corpusFile.write(u"\n") corpusFile.close() 

而当我执行它,我有以下错误:

 (...) in storeTaggedCorpus corpusFile.write(tagged_token) File "c:\Python26\lib\codecs.py", line 691, in write return self.writer.write(data) File "c:\Python26\lib\codecs.py", line 351, in write data, consumed = self.encode(object, self.errors) UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128) 

所以我去debugging它,发现创build的文件被编码为ANSI,而不是在corpusFile = codecs.open(filename, mode = 'w', encoding = 'utf-8')声明的UTF-8。 如果corpusFile.write(tagged_token)被移除,这个函数将会(显然)起作用,并且该文件将被编码为ANSI。 如果相反,我删除tagged_token = tagged_token.encode('utf-8') ,它也将工作, 生成的文件将编码“ANSI作为UTF-8”(???)和拉丁字符将被损坏。 由于我正在分析pt-br文本,这是不可接受的。

我相信,如果corpusFile以UTF-8打开,那么一切都会正常工作,但是我无法正常工作。 我search了网页,但是我发现有关Python / Unicode的所有内容都涉及到其他的东西…所以为什么这个文件总是以ANSI结尾呢? 我在Windows 7 x64中使用Python 2.6,并从Notepad ++获知这些文件编码。

编辑 – 关于corpus参数

我不知道corpusstring的编码。 它是由NLTK的 PlaintextCorpusReader.tag()方法生成的。 根据Notepad ++,原始语料库文件使用UTF-8编码。 tagged_token.decode('ISO-8859-1')只是一个猜测。 我已经尝试将其解码为cp1252,并得到了ISO-8859-1中相同的重叠字符。

当用codec.open('w', encoding='utf8')打开文件时,将字节数组( str对象)写入文件没有意义。 相反,写入unicode对象,如下所示:

 corpusFile = codecs.open(filename, mode = 'w', encoding = 'utf-8') # ... tagged_token = '\xdcml\xe4ut' tagged_token = tagged_token.decode('ISO-8859-1') corpusFile.write(tagged_token) corpusFile.write(u'\n') 

这将写平台相关的行尾字符。

或者 ,打开一个二进制文件并写入已经编码的字符串的字节数组:

 corpusFile = open(filename, mode = 'wb') # ... tagged_token = '\xdcml\xe4ut' tagged_token = tagged_token.decode('ISO-8859-1') corpusFile.write(tagged_token.encode('utf-8')) corpusFile.write('\n') 

这将写平台无关的EOL。 如果你想要一个依赖于平台的EOL ,请打印os.sep而不是'\n'

请注意, Notepad ++中的编码命名是误导性的 : ANSI as UTF-8 你想要的。

尝试使用UTF-8签名(又名BOM)编写文件:

 def storeTaggedCorpus(corpus, filename): corpusFile = codecs.open(filename, mode = 'w', encoding = 'utf-8-sig') for token in corpus: tagged_token = '/'.join(str for str in token) # print(type(tagged_token)); break # tagged_token = tagged_token.decode('cp1252') corpusFile.write(tagged_token) corpusFile.write(u"\n") corpusFile.close() 

请注意,如果tagged_token是一个unicode字符串,这将只能正常工作。 要检查,取消注释在上面的代码中的第一个评论 – 它应该打印<type 'unicode'>

如果tagged_token不是一个Unicode字符串,那么您需要先使用第二条注释行对其进行解码。 (注意:我假设有一个“cp1252”编码,但是如果你确定它是“iso-8859-1”,那么当然你需要改变它。)

如果您从文件中看到“已损坏”字符,则需要确保无论您用于查看该文件的什么都知道该文件是UTF-8编码的。

由此代码创建的文件:

 import codecs for enc in "utf-8 utf-8-sig".split(): with codecs.open(enc + ".txt", mode = 'w', encoding = enc) as corpusFile: tagged_token = '\xdcml\xe4ut' tagged_token = tagged_token.decode('cp1252') # not 'ISO-8859-1' corpusFile.write(tagged_token) # write unicode objects corpusFile.write(u'\n') 

这样确定:

Notepad ++(版本5.7(UNICODE)):UTF-8,不含BOM,UTF-8
Firefox(7.0.1):西方(ISO-8859-1),Unicode(UTF-8)
记事本(Windows 7):UTF-8,UTF-8

把你的UTF-8文件放在UTF-8文件中,尽管在Unix系统上不推荐使用,但是在Windows上,你可以更好地使用其他软件来将你的文件识别为UTF-8编码。