我在理解文本读取和写入文件时遇到了一些大脑失败(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'
答案 0 :(得分:656)
我没有弄乱编码和解码方法,而是在打开文件时更容易指定编码。 io
module(在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模块。 codecs module can cause problems when mixing read()
and readline()
,所以此答案现在推荐使用io模块。
使用编解码器模块中的open方法。
>>>import codecs
>>>f = codecs.open("test", "r", "utf-8")
然后在调用f的read()函数之后,返回一个编码的Unicode对象。
>>>f.read()
u'Capit\xe1l\n\n'
如果您知道文件的编码,那么使用编解码器包将会更加容易混淆。
答案 1 :(得分:98)
用符号
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
的内容与您在编辑器中保存的文件内容进行比较。
答案 2 :(得分:30)
现在,您在Python3中所需要的只是open(Filename, 'r', encoding='utf-8')
[编辑于2016-02-10进行要求澄清]
Python3将编码参数添加到其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支持的任何text encoding。 有关支持的编码列表,请参阅codecs模块。
因此,通过将encoding='utf-8'
作为参数添加到open函数中,文件读取和写入都以utf8完成(现在也是Python中所有内容的默认编码。)
答案 3 :(得分:17)
所以,我找到了我正在寻找的解决方案,即:
print open('f2').read().decode('string-escape').decode("utf-8")
这里有一些非常有用的编解码器。这个特殊的读取允许人们从Python中获取UTF-8表示,将它们复制到ASCII文件中,并将它们读入Unicode。在“string-escape”解码下,斜杠不会加倍。
这允许我想象的那种往返。
答案 4 :(得分: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()
答案 5 :(得分:14)
实际上,这对我在Python 3.2中使用UTF-8编码读取文件非常有用:
import codecs
f = codecs.open('file_name.txt', 'r', 'UTF-8')
for line in f:
print(line)
答案 6 :(得分:6)
您在编码时遇到了一般性问题:如何判断文件的编码是什么?
答案:除非文件格式为此提供,否则您不能。例如,XML以:
开头<?xml encoding="utf-8"?>
仔细选择此标头,以便无论编码如何都可以读取。在你的情况下,没有这样的提示,因此你的编辑和Python都不知道发生了什么。因此,您必须使用codecs
模块并使用codecs.open(path,mode,encoding)
来提供Python中缺少的位。
至于你的编辑器,你必须检查它是否提供了一些设置文件编码的方法。
UTF-8的要点是能够将21位字符(Unicode)编码为8位数据流(因为这是世界上所有计算机都可以处理的唯一内容)。但由于大多数操作系统早于Unicode时代,他们没有合适的工具将编码信息附加到硬盘上的文件中。
下一个问题是Python中的表示。这在comment by heikogerlach中得到了很好的解释。您必须了解您的控制台只能显示ASCII。为了显示Unicode或任何&gt; = 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包含:hex:
0000000: 4361 7069 745c 7863 335c 7861 316e Capit\xc3\xa1n
例如, codecs.open('f2','rb', 'utf-8')
在一个单独的字符中读取所有字符(预期)有没有办法用ASCII写入一个可以工作的文件?
答案:这取决于你的意思。 ASCII不能代表字符&gt; 127.所以你需要一些方法来说“接下来的几个字符意味着什么特别的东西”这就是序列“\ x”的作用。它说:接下来的两个字符是单个字符的代码。 “\ u”使用四个字符将Unicode编码为0xFFFF(65535)。
因此,您无法直接将Unicode写入ASCII(因为ASCII不包含相同的字符)。你可以把它写成字符串转义(如f2中所示);在这种情况下,该文件可以表示为ASCII。或者您可以将其写为UTF-8,在这种情况下,您需要一个8位安全流。
使用decode('string-escape')
的解决方案确实有效,但你必须知道你使用了多少内存:使用codecs.open()
的三倍。
请记住,文件只是一个8位字节序列。位和字节都没有意义。是你说“65意味着'A'”。由于\xc3\xa1
应该变为“à”但计算机无法知道,您必须通过指定编写文件时使用的编码来告诉它。
答案 7 :(得分:6)
要读取Unicode字符串然后发送到HTML,我这样做了:
fileline.decode("utf-8").encode('ascii', 'xmlcharrefreplace')
对python驱动的http服务器很有用。
答案 8 :(得分:6)
除了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
答案 9 :(得分:5)
好吧,你最喜欢的文本编辑器没有意识到\xc3\xa1
应该是字符文字,但它将它们解释为文本。这就是你在最后一行得到双反斜杠的原因 - 它现在是你文件中真正的反斜杠+ xc3
等。
如果您想在Python中读写编码文件,最好使用codecs模块。
在终端和应用程序之间粘贴文本很困难,因为您不知道哪个程序会使用哪种编码来解释您的文本。您可以尝试以下方法:
>>> s = file("f1").read()
>>> print unicode(s, "Latin-1")
Capitán
然后将此字符串粘贴到编辑器中,并确保使用Latin-1存储它。在假设剪贴板没有乱码的情况下,往返应该有效。
答案 10 :(得分:4)
\ x ..序列是特定于Python的东西。它不是通用字节转义序列。
如何实际输入UTF-8编码的非ASCII取决于您的操作系统和/或编辑器。 Here's how you do it in Windows。要让OS X输入具有急性重音的 a ,您只需按选项 + E ,然后 A ,几乎所有OS X中的文本编辑器都支持UTF-8。
答案 11 :(得分:3)
您还可以使用open()
函数,通过替换它来改进原始partial
函数以使用Unicode文件。这个解决方案的优点是您不需要更改任何旧代码。这是透明的。
import codecs
import functools
open = functools.partial(codecs.open, encoding='utf-8')
答案 12 :(得分: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"))
(现在它可以打印出喜欢的内容。)
答案 13 :(得分:0)
通过将整个脚本的默认编码更改为'UTF-8',我发现了最简单的方法:
import sys
reload(sys)
sys.setdefaultencoding('utf8')
任何open
,print
或其他语句将只使用utf8
。
至少对Python 2.7.9
有效。