在Python中使用Unicode (UTF-8)读写文件
在Python中使用Unicode (UTF-8)读写文件
我在理解读写文本文件(Python 2.4)方面遇到了一些困难。
# 这个字符串中含有一个带重音符号的字母a。
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'
所以我在我的最喜欢的编辑器中输入了Capit\xc3\xa1n
,保存在文件f2中。
然后:
>>> 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'
我在这里没有理解到什么?显然有一些重要的魔法(或者好的理解)我没有掌握。在文本文件中,应该输入什么来进行正确的转换?
我真正没有理解到的是,如果来自外部的UTF-8表示无法被Python识别,那么UTF-8表示的意义是什么?也许我应该只是将字符串转储为JSON,并使用它,因为它有一个可ASCII化的表示!更重要的是,有没有一种ASCII表示可以让Python在从文件中读取时识别和解码?如果有,我该如何获得它?
>>> print simplejson.dumps(ss)
'"Capit\u00e1n"'
>>> print >> file('f3','w'), simplejson.dumps(ss)
>>> simplejson.load(open('f3'))
u'Capit\xe1n'
在Python3中,通过在open()
函数中添加encoding='utf-8'
参数,可以实现对文件进行Unicode(UTF-8)的读写。这是因为Python3的open()
函数增加了encoding
参数,用于指定文件的编码方式。默认情况下,编码方式是平台相关的,但可以使用Python支持的任何文本编码。通过将encoding='utf-8'
添加为open()
函数的参数,可以实现文件的读写都以utf-8编码方式进行。
在Python2中,可以使用codecs.open('somefile', encoding='utf-8')
来实现类似的功能。
总结起来,Python3中通过在open()
函数中添加encoding='utf-8'
参数,可以实现对文件的Unicode(UTF-8)读写,而在Python2中可以使用codecs.open()
函数来实现。
Unicode (UTF-8) 在 Python 中读写文件的问题及解决方法
在Python中,Unicode (UTF-8) 的编码格式在读写文件时可能会出现一些问题。本文将介绍问题的原因以及解决方法。
问题的原因是,当使用类似于u'Capit\xe1n\n'
这样的表示方法时,在Python 3.x中应该只是'Capit\xe1n\n'
,并且在Python 3.0和3.1版本中必须使用后一种表示方法。其中的\xe1
表示一个字符,\x
是一个转义序列,表示e1
是一个十六进制数。
当我们将Capit\xc3\xa1n
写入文件时,实际上文件中包含的是\xc3\xa1
。这是8个字节,代码会将其全部读取。我们可以通过显示结果来验证这一点:
# Python 3.x - 以字节而不是文本的形式读取文件,确保我们看到原始数据 open('f2', 'rb').read() b'Capit\\xc3\\xa1n\n' # Python 2.x open('f2').read() 'Capit\\xc3\\xa1n\n'
相反,我们可以在文本编辑器中直接输入像á
这样的字符,编辑器会自动将其转换为UTF-8编码并保存。
在Python 2.x中,一个包含这些反斜杠转义序列的字符串可以使用string_escape
编解码器进行解码:
# Python 2.x 'Capit\\xc3\\xa1n\n'.decode('string_escape')
结果是一个以UTF-8编码的str
,其中带有重音的字符由原始字符串中的\\xc3\\xa1
表示。要获得unicode
结果,需要再次使用UTF-8进行解码。
在Python 3.x中,string_escape
编解码器被unicode_escape
取代,并且严格执行以下规则:只能将str
编码为bytes
,将bytes
解码为str
。为了处理转义序列,unicode_escape
需要以bytes
开头(反之亦然,它会将转义序列添加进去),然后将结果中的\xc3
和\xa1
视为字符转义而不是字节转义。因此,我们需要进行更多的操作:
# Python 3.x 'Capit\\xc3\\xa1n\n'.encode('ascii').decode('unicode_escape').encode('latin-1').decode('utf-8')
那么,为什么要使用UTF-8编码格式,而Python却可以使用它来读取文件呢?换句话说,是否存在某种ASCII表示形式,Python可以将\xC3读取为1个字节?
关于你的“那么,为什么要使用…”的问题的答案是“Mu.”(因为Python可以读取以UTF-8编码的文件)。至于你的第二个问题:\xC3不是ASCII字符集的一部分。也许你是指“8位编码”。你对Unicode和编码的概念有些混淆,没关系,很多人都有这样的问题。
建议阅读这篇文章作为入门:[joelonsoftware.com/articles/Unicode.html](http://www.joelonsoftware.com/articles/Unicode.html)
注意:u'\xe1'
是一个Unicode码点[U+00e1](http://codepoints.net/U+00e1),它可以根据字符编码使用1个或多个字节进行表示(在UTF-8中是2个字节)。b'\xe1'
是一个字节(数字225),它可以根据所使用的字符编码来解码成一个字母,例如在cp1251中是[б (U+0431)](http://codepoints.net/U+0431),在cp866中是[с (U+0441)](http://codepoints.net/U+0441)等。
令人惊讶的是,有多少英国程序员说“只使用ascii”,然后却没有意识到£符号不属于ascii字符集。他们大多不知道ascii!=本地代码页(即latin1)。
对于你最后的问题,在Python 3.x中,将字节写入文件会导致错误消息“write() argument must be str, not bytes”,无论是在Python 2还是Python 3.7中都是如此。
是的,在Python 3.x中,对字符串使用.encode
将产生一个bytes
对象,只能将其写入以二进制模式打开的文件中。在Python 2.x中应该可以正常工作,因为2.x版本对文本的处理有错误,bytes
被假装成字符串(在2.7中,我不确定这个错误从哪个版本开始出现,str
实际上是bytes
的别名,而unicode
是真正的字符串类型)。
Python中读写Unicode(UTF-8)文件的原因是为了处理编码问题。如果使用.encode
和.decode
方法,可能会导致混乱和错误。解决方法是在打开文件时指定编码,可以使用io.open
函数或codecs.open
函数。
在Python 2.6之后的版本中,可以使用io.open
函数指定文件的编码。例如,如果文件编码为UTF-8,可以使用以下代码打开文件:
import io f = io.open("test", mode="r", encoding="utf-8")
然后,使用f.read
方法读取文件,返回一个解码后的Unicode对象。例如:
f.read() # 返回 u'Capit\xe1l\n\n'
在Python 3.x中,io.open
函数是内置的open
函数的别名,支持encoding
参数。在Python 2.x中,open
函数不支持encoding
参数。另外,也可以使用codecs.open
函数来打开文件,该函数是标准库模块codecs
中的函数。例如:
import codecs f = codecs.open("test", "r", "utf-8") f.read() # 返回 u'Capit\xe1l\n\n'
需要注意的是,使用codecs.open
函数可能会在混合使用read()
和readline()
方法时出现问题。
此外,codecs.open
函数也可以与with open(...):
语法结合使用,确保在完成操作后自动关闭文件。例如:
with codecs.open(...) as f: # 文件操作
如果文件可能包含BOM(字节顺序标记),可以使用encoding="utf-8-sig"
。例如,在Python 2.7中使用codecs.open
函数打开文件:
codecs.open(file, 'w', 'utf-8-sig')
以上是关于在Python中读写Unicode(UTF-8)文件的原因和解决方法的说明。这些方法可以有效地处理编码问题,确保文件的正确读写。