如何在Python 2.7中一次解码一行unicode?

时间:2012-08-08 14:20:39

标签: python python-2.7 file-io unicode generator

从Python 2.7加载unicode文本的正确方法如下:

content = open('filename').read().decode('encoding'):
for line in content.splitlines():
    process(line)

更新:不,不是。请参阅答案。)

但是,如果文件非常大,我可能希望一次读取,解码和处理一行,这样整个文件就不会一次加载到内存中。类似的东西:

for line in open('filename'):
    process(line.decode('encoding'))        

for循环对打开文件句柄的迭代是一次读取一行的生成器。

但这不起作用,因为如果文件是utf32编码的,那么文件中的字节(十六进制)看起来像:

hello\n = 68000000(h) 65000000(e) 6c000000(l) 6c000000(l) 6f000000(o) 0a000000(\n)

for循环分割成的行分为0a字符的\n字节,导致(以十六进制):

lines[0] = 0x 68000000 65000000 6c000000 6c000000 6f000000 0a
lines[1] = 0x 000000

因此\n字符的一部分留在第1行的末尾,其余三个字节在第2行结束(后面跟着第2行中的任何文本。)调用decode在这两行中的任何一行都可以理解为UnicodeDecodeError

UnicodeDecodeError: 'utf32' codec can't decode byte 0x0a in position 24: truncated data

因此,显然,在0a字节上拆分unicode字节流不是将其拆分为行的正确方法。相反,我应该分裂出现完整的四字节换行符(0x0a000000)。但是,我认为检测这些字符的正确方法是将字节流解码为unicode字符串并查找\n个字符 - 这个完整流的解码正是我试图避免的操作。 / p>

这不是一个不常见的要求。处理它的正确方法是什么?

4 个答案:

答案 0 :(得分:7)

尝试类似的事情:

for line in codecs.open("filename", "rt", "utf32"):
    print line

我认为这应该有用。

codecs模块应该为您进行翻译。

答案 1 :(得分:4)

尝试使用编解码器模块:

for line in codecs.open(filename, encoding='utf32'):
    do_something(line)

答案 2 :(得分:1)

使用codecs.open而不是builtin open:

import codecs
for line in codecs.open('filename', encoding='encoding'):
    print repr(line)

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

当然,我在完成精心设计的stackoverflow问题后发现了这一点。

答案 3 :(得分:1)

codecs.open itself notes that io.open is a better option(注意就在链接目标之上)。它不被弃用,只是因为它支持一些深奥的用法(字节 - >字节编解码器)。

io.open is available in Python 2.6 and higher,并提供与Py3的内置open相同的行为,更好地优化,并且在codecs.open时不会像codecs.open那样行为不端像行结束转换的东西。使用io.open的唯一原因是,如果您需要支持Python 2.5及更早版本,否则import io # Use with statement for guaranteed, predictable cleanup with io.open('filename', encoding='utf-32') as f: for line in f: process(line) 严格来说更好。

def process_file(f):
    if 'b' in f.mode:  # Or some better test...
        f = io.TextIOWrapper(f, encoding='utf-32')
    for line in f:
        process(line)

顺便提一下,您可以将任何已打开的二进制文件类对象转换为基于无缝解码文本的对象using io.TextIOWrapper,因此如果其他人以二进制文件为您提供现有的类文件对象模式,您仍然可以使用以下方式进行逐行解码:

SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd" );
Calendar cal = Calendar.getInstance();
cal.setTime( dateFormat.parse( inputString ) );
cal.add( Calendar.DATE, 7 );