我在理解读取和写入文件的文本方面有一些大脑故障(Python 2.4)。

# The string, which has an a-acute in it.
ss = u'Capit\xe1n'
ss8 = ss.encode('utf8')
repr(ss), repr(ss8)

(“u’Capit \ xe1n’”、“’Capit \ xc3 \ xa1n’")

print ss, ss8
print >> open('f1','w'), ss8

>>> file('f1').read()
'Capit\xc3\xa1n\n'

于是我在我最喜欢的编辑器f2文件中输入了大写字母\xc3\xa1n。

然后:

>>> open('f1').read()
'Capit\xc3\xa1n\n'
>>> open('f2').read()
'Capit\\xc3\\xa1n\n'
>>> open('f1').read().decode('utf8')
u'Capit\xe1n\n'
>>> open('f2').read().decode('utf8')
u'Capit\\xc3\\xa1n\n'

我哪里不明白了?显然,我忽略了一些至关重要的魔力(或良好的感觉)。在文本文件中输入什么才能得到正确的转换?

我在这里真正搞不懂的是,当它来自外部时,如果你不能让Python识别它,那么UTF-8表示的意义是什么。也许我应该只是JSON转储字符串,并使用它,因为它有一个asciiable表示!更重要的是,当这个Unicode对象从文件中传入时,是否存在Python能够识别和解码的ASCII表示形式?如果有,我怎么得到它?

>>> print simplejson.dumps(ss)
'"Capit\u00e1n"'
>>> print >> file('f3','w'), simplejson.dumps(ss)
>>> simplejson.load(open('f3'))
u'Capit\xe1n'

当前回答

在符号u'Capit\xe1n\n'(应该是'Capit\xe1n\n'在3。X,并且必须在3.0和3.1中),\xe1只代表一个字符。\x是转义序列,表示e1是十六进制。

在文本编辑器中将Capit\xc3\xa1n写入文件中意味着它实际上包含\xc3\xa1。这是8个字节,代码会全部读取。我们可以通过显示结果来看到这一点:

# Python 3.x - reading the file as bytes rather than text,
# to ensure we see the raw data
>>> open('f2', 'rb').read()
b'Capit\\xc3\\xa1n\n'

# Python 2.x
>>> open('f2').read()
'Capit\\xc3\\xa1n\n'

相反,只需在编辑器中输入像á这样的字符,然后编辑器将处理转换为UTF-8并保存它。

在2。X,实际上包含这些反斜杠转义序列的字符串可以使用string_escape编解码器解码:

# Python 2.x
>>> print 'Capit\\xc3\\xa1n\n'.decode('string_escape')
Capitán

结果是一个以UTF-8编码的str,其中重音字符由在原始字符串中写入\\xc3\\xa1的两个字节表示。要获得unicode结果,再次使用UTF-8解码。

在3。在X中,string_escape编解码器被unicode_escape取代,并且严格强制我们只能从STR编码到字节,并从字节解码到STR。unicode_escape需要从字节开始以便处理转义序列(相反,它会添加它们);然后它会把结果\xc3和\xa1当作字符转义,而不是字节转义。因此,我们必须做更多的工作:

# Python 3.x
>>> 'Capit\\xc3\\xa1n\n'.encode('ascii').decode('unicode_escape').encode('latin-1').decode('utf-8')
'Capitán\n'

其他回答

在符号u'Capit\xe1n\n'(应该是'Capit\xe1n\n'在3。X,并且必须在3.0和3.1中),\xe1只代表一个字符。\x是转义序列,表示e1是十六进制。

在文本编辑器中将Capit\xc3\xa1n写入文件中意味着它实际上包含\xc3\xa1。这是8个字节,代码会全部读取。我们可以通过显示结果来看到这一点:

# Python 3.x - reading the file as bytes rather than text,
# to ensure we see the raw data
>>> open('f2', 'rb').read()
b'Capit\\xc3\\xa1n\n'

# Python 2.x
>>> open('f2').read()
'Capit\\xc3\\xa1n\n'

相反,只需在编辑器中输入像á这样的字符,然后编辑器将处理转换为UTF-8并保存它。

在2。X,实际上包含这些反斜杠转义序列的字符串可以使用string_escape编解码器解码:

# Python 2.x
>>> print 'Capit\\xc3\\xa1n\n'.decode('string_escape')
Capitán

结果是一个以UTF-8编码的str,其中重音字符由在原始字符串中写入\\xc3\\xa1的两个字节表示。要获得unicode结果,再次使用UTF-8解码。

在3。在X中,string_escape编解码器被unicode_escape取代,并且严格强制我们只能从STR编码到字节,并从字节解码到STR。unicode_escape需要从字节开始以便处理转义序列(相反,它会添加它们);然后它会把结果\xc3和\xa1当作字符转义,而不是字节转义。因此,我们必须做更多的工作:

# Python 3.x
>>> 'Capit\\xc3\\xa1n\n'.encode('ascii').decode('unicode_escape').encode('latin-1').decode('utf-8')
'Capitán\n'

我找到了最简单的方法,将整个脚本的默认编码改为'UTF-8':

import sys
reload(sys)
sys.setdefaultencoding('utf8')

任何打开、打印或其他语句将只使用utf8。

至少适用于Python 2.7.9。

谢谢到https://markhneedham.com/blog/2015/05/21/python-unicodeencodeerror-ascii-codec-cant-encode-character-uxfc-in-position-11-ordinal-not-in-range128/(看最后)。

现在你在Python3中所需要的就是open(Filename, 'r', encoding='utf-8')

[编辑于2016-02-10,要求澄清]

Python3将encoding参数添加到其open函数中。open函数的相关信息如下:https://docs.python.org/3/library/functions.html#open

open(file, mode='r', buffering=-1, 
      encoding=None, errors=None, newline=None, 
      closefd=True, opener=None)

编码是用于解码或编码的编码的名称 文件。这应该只在文本模式中使用。默认编码为 平台相关(无论locale.getpreferredencoding()) 返回),但可以使用Python支持的任何文本编码。 有关支持的编码列表,请参阅codecs模块。

因此,通过将encoding='utf-8'作为参数添加到open函数中,文件读写都以utf8完成(这也是Python中所有操作的默认编码)。

您还可以改进原始的open()函数,通过使用partial函数替换它来处理Unicode文件。这个解决方案的美妙之处在于您不需要更改任何旧代码。它是透明的。

import codecs
import functools
open = functools.partial(codecs.open, encoding='utf-8')

我试图用Python 2.7.9解析iCal:

从icalendar导入日历

但我得到:

 Traceback (most recent call last):
 File "ical.py", line 92, in parse
    print "{}".format(e[attr])
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe1' in position 7: ordinal not in range(128)

它只是用:

print "{}".format(e[attr].encode("utf-8"))

(现在它可以打印liké á böss。)