Unicode (UTF-8) 在 Python 中读取和写入文件

新手上路,请多包涵

我在理解读取文本和将文本写入文件(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 中输入 Capit\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'

我在这里不明白什么?显然,我缺少一些重要的魔法(或良好的感觉)。一种输入文本文件以进行正确转换的方法是什么?

我在这里真正无法理解的是 UTF-8 表示的意义是什么,如果你不能真正让 Python 识别它,当它来自外部时。也许我应该只是 JSON 转储字符串,并改用它,因为它有一个 asciiable 表示!更重要的是,当从文件进入时,Python 会识别和解码这个 Unicode 对象的 ASCII 表示吗?如果是这样,我该如何得到它?

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

原文由 Gregg Lind 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 630
2 个回答

在符号 u'Capit\xe1n\n' (在3.x中应该只是 'Capit\xe1n\n' ,并且 必须 在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

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

In 3.x, the string_escape codec is replaced with unicode_escape , and it is strictly enforced that we can only encode from a strbytesdecodebytesstr 2b8f1425790f58e2b84d —d。 unicode_escape 需要以 --- 开头以处理转义序列( bytes ,它 会添加 它们);然后它将生成的 \xc3\xa1 视为 字符 转义而不是 字节 转义。因此,我们必须做更多的工作:

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

原文由 unbeknown 发布,翻译遵循 CC BY-SA 4.0 许可协议

而不是 .encode.decode ,在打开文件时指定编码。 Python 2.6 中添加的 io 模块 提供了一个 io.open 函数,它允许指定文件的 encoding

假设文件以 UTF-8 编码,我们可以使用:

 >>> import io
>>> f = io.open("test", mode="r", encoding="utf-8")

然后 f.read 返回解码后的Unicode对象:

 >>> f.read()
u'Capit\xe1l\n\n'

在3.x中, io.open 函数是内置 open 函数的别名,它支持 encoding 参数(不在–2 ).

我们还可以使用 open 来自 codecs 标准库模块

 >>> import codecs
>>> f = codecs.open("test", "r", "utf-8")
>>> f.read()
u'Capit\xe1l\n\n'

但是请注意,这 在混合 read()readline() 时可能会导致问题

原文由 Tim Swast 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题