Unicode转义文件处理错误

5

我有一个原始文本文件,只包含以下行,没有换行符:

Q853 \u0410\u043D\u0434\u0440\u0435\u0439 \u0410\u0440\u0441\u0435\u043D\u044C\u0435\u0432\u0438\u0447 \u0422\u0430\u0440\u043A\u043E\u0432\u0441\u043A\u0438\u0439

如上所示,字符被转义,这意味着\u05E9实际上是一个反斜杠,后面跟着5个字母数字字符(而不是Unicode字符)。我正在尝试使用以下代码解码文件:

import codecs

with codecs.open("wikidata-terms20.nt", 'r', encoding='unicode_escape') as input:
    with open("wikidata-terms3.nt", "w") as output:
        for line in input:
            output.write(line)

这里不能使用print,请查看注释。

运行它会给出以下错误:

Traceback (most recent call last):
  File "terms2.py", line 5, in <module>
    for line in input:
  File "C:\Program Files\Python35\lib\codecs.py", line 711, in __next__
    return next(self.reader)
  File "C:\Program Files\Python35\lib\codecs.py", line 642, in __next__
    line = self.readline()
  File "C:\Program Files\Python35\lib\codecs.py", line 555, in readline
    data = self.read(readsize, firstline=True)
  File "C:\Program Files\Python35\lib\codecs.py", line 501, in read
newchars, decodedbytes = self.decode(data, self.errors)
UnicodeDecodeError: 'unicodeescape' codec can't decode bytes in position 67-71: truncated \uXXXX escape

发生了什么?

我正在Windows 8.1上运行Python 3.5.1,并且该代码似乎适用于大多数其他Unicode字符(这一行是导致崩溃的第一行)。

请参见编辑历史记录以获取原始问题。


导致错误的第一行是 Q501 \u05E9\u05D0\u05E8\u05DC \u05D1\u05D5\u05D3\u05DC\u05E8,如果无法解码第一个字符。但是 U+05E9 似乎是有效的 Unicode。 - pie3636
这是文件的十六进制转储:http://pastebin.com/cELKNSWk - pie3636
1
这是一个打印输出的问题。请注意错误信息中提到了 cp850 编码。请查看 Python、Unicode 和 Windows 控制台 - roeland
1
在我的Windows 7上复现,现在将进行调试。 - Leon
1
我并不完全理解这个问题,但似乎找到了一个解决方法。请看我的回答。 - Leon
显示剩余10条评论
1个回答

2
似乎解码器读取的数据在第72个字符(从0开始计数的第71个字符)之后被截断了。这显然与这个Bug有某种关联。
以下代码产生了与您示例中相同的错误:
open("wikidata-terms20.nt", 'r').readline()
open("wikidata-terms20.nt", 'r').readline(72)

将readline的大小增加到输入实际大小以上,或将其设置为-1,则可消除错误:

open("wikidata-terms20.nt", 'r').readline(1000)
open("wikidata-terms20.nt", 'r').readline(-1)

显然,for line in input: 通过 readline() 获取要解码的行,有效地将待解码的数据截断为72个字符。
因此,这里有几个解决方法: 解决方法1:
import codecs

with open("wikidata-terms20.nt", 'r') as input:
    with open("wikidata-terms3.nt", "w") as output:
        for line in input:
            output.write(codecs.decode(line, 'unicode_escape'))

解决方法2:

import codecs

with codecs.open("wikidata-terms20.nt", 'r', encoding='unicode_escape') as input:
    with open("wikidata-terms3.nt", "w") as output:
        for line in input.readlines():
            output.write(line)

谢谢,那个完美地解决了问题!顺便提一下,我不得不在output.write行中指定encoding='utf-8'才能避免失败。 - pie3636

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接