【问题标题】:How do I decode unicode one line at a time in Python 2.7?如何在 Python 2.7 中一次解码 unicode 一行?
【发布时间】:2012-08-05 16:24:54
【问题描述】:

从 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 循环完成的拆分成行在\n 字符的0a 字节上拆分,导致(十六进制):

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

因此,很明显,将 unicode 字节流拆分为 0a 字节并不是将其拆分为行的正确方法。相反,我应该在出现完整的四字节换行符 (0x0a000000) 时进行拆分。但是,我认为检测这些字符的正确方法是将字节流解码为 un​​icode 字符串并查找 \n 字符 - 而这种对完整流的解码正是我试图避免的操作。

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

【问题讨论】:

  • 您是否尝试使用 codecs.open() 方法读取文件?
  • @Maulwurfn,我不知道它存在!但我现在这样做。谢谢。

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


【解决方案1】:

试试类似的东西怎么样:

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

我认为这应该可行。

codecs 模块应该为您完成翻译。

【讨论】:

  • 读者!另请参阅本页底部附近 ShadowRanger 的低点回答:“codecs.open docs note that io.open is a better option” ...
【解决方案2】:

尝试使用编解码器模块:

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

【讨论】:

  • 我选择了@Simon 的答案,只是因为他的分数较少,但有一个赞成票。谢谢!
【解决方案3】:

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 的唯一原因是如果您需要支持 Python 2.5 及更早版本,否则,io.open 绝对更好。

import io

# Use with statement for guaranteed, predictable cleanup
with io.open('filename', encoding='utf-32') as f:
    for line in f:
        process(line)

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

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)

【讨论】:

    【解决方案4】:

    使用 codecs.open 代替内置 open:

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

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

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

    【讨论】:

      猜你喜欢
      • 2019-06-19
      • 1970-01-01
      • 2013-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-04
      • 2014-05-09
      相关资源
      最近更新 更多