372

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

所以我在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 识别它,当它来自外部时。也许我应该只是 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'
4

14 回答 14

818

我发现在打开文件时指定编码更容易,而不是弄乱编码和解码方法。该io模块(在 Python 2.6 中添加)提供了一个io.open函数,该函数具有一个编码参数。

使用io模块中的 open 方法。

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

然后在调用 f 的 read() 函数后,返回一个编码的 Unicode 对象。

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

请注意,在 Python 3 中,该io.open函数是内置函数的别名open。内置的 open 函数仅支持 Python 3 中的 encoding 参数,不支持 Python 2。

编辑:以前这个答案推荐了编解码器模块。codecs 模块在混合 和 时可能会导致问题read()readline()因此这个答案现在推荐使用io模块。

使用编解码器模块中的 open 方法。

>>>import codecs
>>>f = codecs.open("test", "r", "utf-8")

然后在调用 f 的 read() 函数后,返回一个编码的 Unicode 对象。

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

如果您知道文件的编码,那么使用 codecs 包就不会那么混乱了。

请参阅http://docs.python.org/library/codecs.html#codecs.open

于 2009-05-10T00:45:58.417 回答
115

在符号

u'Capit\xe1n\n'

"\xe1" 只代表一个字节。"\x" 告诉你 "e1" 是十六进制的。当你写

Capit\xc3\xa1n

在你的文件中你有“\xc3”。这些是 4 个字节,在您的代码中您可以全部阅读它们。显示它们时可以看到:

>>> open('f2').read()
'Capit\\xc3\\xa1n\n'

您可以看到反斜杠被反斜杠转义。所以你的字符串中有四个字节:“\”、“x”、“c”和“3”。

编辑:

正如其他人在他们的回答中指出的那样,您应该只在编辑器中输入字符,然后您的编辑器应该处理转换为 UTF-8 并保存它。

如果您确实有这种格式的字符串,则可以使用string_escape编解码器将其解码为普通字符串:

In [15]: print 'Capit\\xc3\\xa1n\n'.decode('string_escape')
Capitán

结果是一个以 UTF-8 编码的字符串,其中重音字符由写入\\xc3\\xa1原始字符串的两个字节表示。如果你想要一个 unicode 字符串,你必须用 UTF-8 再次解码。

对您的编辑:您的文件中没有 UTF-8。要实际查看它的外观:

s = u'Capit\xe1n\n'
sutf8 = s.encode('UTF-8')
open('utf-8.out', 'w').write(sutf8)

将文件utf-8.out内容与您使用编辑器保存的文件内容进行比较。

于 2009-01-29T15:11:59.337 回答
69

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

[在 2016-02-10 上编辑要求澄清]

Python3 在其 open 函数中添加了encoding参数。以下关于 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)

Encoding 是用于对文件进行解码或编码的编码名称。这应该只在文本模式下使用。默认编码取决于平台(无论locale.getpreferredencoding() 返回什么),但可以使用 Python 支持的任何文本编码。有关支持的编码列表,请参阅编解码器模块。

因此,通过将encoding='utf-8'作为参数添加到 open 函数,文件的读取和写入都以 utf8 的形式完成(这也是现在 Python 中所做的一切的默认编码。)

于 2016-02-10T16:03:00.400 回答
18

实际上,这对我在 Python 3.2 中读取具有 UTF-8 编码的文件很有用:

import codecs
f = codecs.open('file_name.txt', 'r', 'UTF-8')
for line in f:
    print(line)
于 2014-08-19T08:09:28.090 回答
17

所以,我找到了我正在寻找的解决方案,即:

print open('f2').read().decode('string-escape').decode("utf-8")

有一些不寻常的编解码器在这里很有用。这种特殊的读取允许人们从 Python 中获取 UTF-8 表示,将它们复制到 ASCII 文件中,然后将它们读入 Unicode。在“字符串转义”解码下,斜线不会加倍。

这允许我想象中的那种往返旅行。

于 2009-01-29T20:01:27.303 回答
14
# -*- encoding: utf-8 -*-

# converting a unknown formatting file in utf-8

import codecs
import commands

file_location = "jumper.sub"
file_encoding = commands.getoutput('file -b --mime-encoding %s' % file_location)

file_stream = codecs.open(file_location, 'r', file_encoding)
file_output = codecs.open(file_location+"b", 'w', 'utf-8')

for l in file_stream:
    file_output.write(l)

file_stream.close()
file_output.close()
于 2012-02-08T20:24:46.897 回答
7

除了codecs.open(), 可以 使用io.open()Python2 或 Python3 来 读 / 写 unicode 文件

例子

import io

text = u'á'
encoding = 'utf8'

with io.open('data.txt', 'w', encoding=encoding, newline='\n') as fout:
    fout.write(text)

with io.open('data.txt', 'r', encoding=encoding, newline='\n') as fin:
    text2 = fin.read()

assert text == text2
于 2017-06-21T09:37:44.937 回答
6

好吧,您最喜欢的文本编辑器并没有意识到\xc3\xa1应该是字符文字,但它会将它们解释为文本。这就是为什么你在最后一行得到双反斜杠的原因——它现在是xc3你文件中真正的反斜杠 + 等等。

如果你想在 Python 中读写编码文件,最好使用codecs模块。

在终端和应用程序之间粘贴文本很困难,因为您不知道哪个程序会使用哪种编码来解释您的文本。您可以尝试以下方法:

>>> s = file("f1").read()
>>> print unicode(s, "Latin-1")
Capitán

然后将此字符串粘贴到您的编辑器中,并确保它使用 Latin-1 存储它。在剪贴板不会乱码字符串的假设下,往返应该可以工作。

于 2009-01-29T15:13:11.050 回答
6

您偶然发现了编码的一般问题:如何判断文件是哪种编码?

答:除非文件格式提供了这一点,否则您不能这样做。例如,XML 以:

<?xml encoding="utf-8"?>

此标头经过精心选择,以便无论编码如何都可以读取。在您的情况下,没有这样的提示,因此您的编辑器和 Python 都不知道发生了什么。因此,您必须使用codecs模块并使用codecs.open(path,mode,encoding)它提供 Python 中缺少的位。

至于您的编辑器,您必须检查它是否提供了一些设置文件编码的方法。

UTF-8 的重点是能够将 21 位字符 (Unicode) 编码为 8 位数据流(因为这是世界上所有计算机都可以处理的唯一内容)。但由于大多数操作系统早于 Unicode 时代,它们没有合适的工具将编码信息附加到硬盘上的文件中。

下一个问题是 Python 中的表示。heikogerlach的评论完美地解释了这一点。您必须了解您的控制台只能显示 ASCII。为了显示 Unicode 或任何 >= charcode 128,它必须使用某种转义方法。在您的编辑器中,您不能输入转义的显示字符串,而是输入字符串的含义(在这种情况下,您必须输入变音符号并保存文件)。

也就是说,您可以使用 Python 函数 eval() 将转义字符串转换为字符串:

>>> x = eval("'Capit\\xc3\\xa1n\\n'")
>>> x
'Capit\xc3\xa1n\n'
>>> x[5]
'\xc3'
>>> len(x[5])
1

如您所见,字符串“\xc3”已变成单个字符。现在这是一个 8 位字符串,采用 UTF-8 编码。要获取 Unicode:

>>> x.decode('utf-8')
u'Capit\xe1n\n'

Gregg Lind问:我认为这里缺少一些部分:文件 f2 包含:十六进制:

0000000: 4361 7069 745c 7863 335c 7861 316e  Capit\xc3\xa1n

codecs.open('f2','rb', 'utf-8'),例如,以单独的字符读取它们(预期) 有什么方法可以用 ASCII 写入文件吗?

答:这取决于你的意思。ASCII 不能表示大于 127 的字符。所以你需要某种方式来表示“接下来的几个字符意味着一些特殊的东西”,这就是序列“\x”所做的。它说:接下来的两个字符是单个字符的代码。"\u" 使用四个字符将 Unicode 编码为 0xFFFF (65535) 也是如此。

所以你不能直接将 Unicode 写入 ASCII(因为 ASCII 根本不包含相同的字符)。您可以将其写为字符串转义符(如 f2 中);在这种情况下,文件可以表示为 ASCII。或者您可以将其编写为 UTF-8,在这种情况下,您需要一个 8 位安全流。

您的解决方案 usingdecode('string-escape')确实有效,但您必须知道您使用了多少内存:使用量的三倍codecs.open()

请记住,文件只是一个 8 位的字节序列。位和字节都没有意义。是你说“65 意味着 'A'”。由于\xc3\xa1应该变成“à”但计算机无法知道,因此您必须通过指定写入文件时使用的编码来告诉它。

于 2009-01-29T16:54:42.173 回答
6

要读取 Unicode 字符串然后发送到 HTML,我这样做了:

fileline.decode("utf-8").encode('ascii', 'xmlcharrefreplace')

对于 python 驱动的 http 服务器很有用。

于 2014-09-18T14:38:14.433 回答
4

\x.. 序列是 Python 特有的。它不是通用的字节转义序列。

您实际输入 UTF-8 编码的非 ASCII 的方式取决于您的操作系统和/或您的编辑器。这是您在 Windows 中执行此操作的方法。要让 OS X 输入带有重音符号的 a,您只需点击+optionE然后A,几乎所有 OS X 中的文本编辑器都支持 UTF-8。

于 2009-01-29T15:10:26.733 回答
3

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

import codecs
import functools
open = functools.partial(codecs.open, encoding='utf-8')
于 2016-12-08T03:22:48.147 回答
1

我试图使用 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"))

(现在它可以像 böss 一样打印了。)

于 2016-05-10T12:49:41.953 回答
-1

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

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

anyopenprint其他语句将只使用utf8.

至少适用于Python 2.7.9.

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

于 2019-12-17T14:49:38.913 回答