使用Python 3.6读取文件

使用Python 3.6读取文件,python,python-3.x,character-encoding,Python,Python 3.x,Character Encoding,你好,我和艾伦·唐尼的奥雷利书一起学习Python 3.x。在第9章中有一个使用Moby项目文件中的单词列表的示例 我阅读了带有以下Python行的german.txt文件 以open(“derman.txt”)作为日志的: 对于日志中的行: word=line.strip() 如果len(word)>20: 打印(word) 读了一些单词,但是有一个停顿,我明白了这句话 Amtsueberschreitungen Traceback (most recent call last):

你好,我和艾伦·唐尼的奥雷利书一起学习Python 3.x。在第9章中有一个使用Moby项目文件中的单词列表的示例

我阅读了带有以下Python行的german.txt文件

以open(“derman.txt”)作为日志的
:
对于日志中的行:
word=line.strip()
如果len(word)>20:
打印(word)
读了一些单词,但是有一个停顿,我明白了这句话

Amtsueberschreitungen
Traceback (most recent call last):
  File "einlesen.py", line 8, in <module>
    for line in log:
  File "/home/alexander/anaconda3/lib/python3.6/codecs.py", line 321, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 394: invalid start byte
Amtsueberschreitungen
回溯(最近一次呼叫最后一次):
文件“einlesen.py”,第8行,在
对于日志中的行:
文件“/home/alexander/anaconda3/lib/python3.6/codecs.py”,第321行,解码中
(结果,消耗)=自身缓冲区解码(数据,自身错误,最终)
UnicodeDecodeError:“utf-8”编解码器无法解码位置394中的字节0x82:无效的开始字节
符号是什么意思?我如何用python代码处理这个问题


谢谢

根据我上面的评论,这看起来像是一个编码问题,经过测试后,基本上就是这样

使用以下命令检测编码:

这不是Python的默认
UTF8
-编码。为了使用其他编码读取文件,您需要使用
open(filename,mode,encoding,…)
函数的
encoding=
参数指定读取文件时所需的编码

由于编码可能事先不知道,因此可以很方便地确定文件编码,然后将其传递给文件读取,如下所示:

from chardet.universaldetector import UniversalDetector

detector = UniversalDetector()
detector.reset()
with open('german.txt', 'rb') as file:
    for line in file:
        detector.feed(line)
        if detector.done:
            break
detector.close()
encoding = detector.result
print(encoding)

with open("german.txt", encoding=encoding) as log:
    for line_num, line in enumerate(log):
        word = line.strip()
        if len(word) > 20:
            print(line_num, word)

注意:在我的机器上使用德国语言环境(MacOS 10.10.5和Python 3.6.2)可以正常工作,并且在检测编码之前得到了与OP相同的错误。我的地区是:


猜测文件的正确编码可能很棘手。让我们首先以二进制模式打开文件,找到有问题的字节,并检查周围的字符

>>> with open('german.txt', 'rb') as f:
...     bs = f.read()
... 
>>> bs.find(b'\x82')
24970
>>> bs[24960:24980]
b'nebel\rAndr\x82\rAndy\rAne'
因此字节b'\x82'是以“Andr”开头的五个字母单词中的最后一个字母

在中查找b'\x82'(由堆栈溢出用户@tripleee),我们可以看到它可能匹配哪些字符。我认为最有可能的匹配是“埃”,给我们起了一个恰当的名字“安德烈”。对照,最合适的编码是cp850,这是西欧语言的传统编码

此代码将无错误地读取文件:

>>> with open('german.txt', encoding='cp850') as f:
...     for line in f:
...         # do things with line
如果在数据中发现任何“异常”字符,则可能需要尝试其他编码。这是因为8位编码很可能成功解码一个字节,但结果毫无意义。例如,如果我们从cp1252解码:

>>> b'Andr\x82'.decode('cp1252')
'Andr‚'
根据报告:

如果未指定编码,则使用的编码依赖于平台:locale。将调用getpreferredencoding(False)以获取当前的语言环境编码

因此,如何读取文件对每个人来说都是不同的。要保证正确读取文件,需要指定正确的编码

根据“一些非ASCII重音字符仍然存在,使用Mac OS罗马编码表示”。在中,您可以找到该编解码器的正确名称,即“mac_roman”。因此,您可以使用以下代码,这不会导致解码错误:

以open(“derman.txt”,“rt”,encoding='mac_roman')作为日志:
对于日志中的行:
word=line.strip()
如果len(word)>20:
打印(word)
更新

尽管有文档,但该文件似乎没有使用Mac OS Roman编码。我用计算机解码了文件,并比较了结果。列表中只有9个非ASCII单词,“André”一词似乎是正确的,正如另一个答案所指出的。以下是可能的编码列表(没有失败,包括单词“André”)和根据该编码解码的9个非ASCII单词:

编码:cp437、cp860、cp861、cp863、cp865
单词:安德烈、随员、夏多、指挥官、塞尚、法贝里、列维·施特劳斯、罗内塔尔、p≥安格
编码:cp720
单词:安德烈、随从、夏图、法国总统、塞尚、法贝里、列维·施特劳斯、罗内塔尔、安格
编码:cp775
词语:安德烈、随员、奇托、指挥官、塞尚、法贝里、列维·施特劳斯、莱内塔尔、安格
编码:cp850,cp858
单词:安德烈、随从、夏图、法国总统、塞尚、法贝里、列维·施特劳斯、罗内塔尔、安格
编码:cp852
词语:安德烈、随从、夏图、法国总统、塞尚、法贝里、列维·施特劳斯、罗内塔尔、潘格
对于上述所有编码,解码时前8个字是相同的。只有最后一个字有9个不同的结果


根据这一结果,我认为使用了cp720编码。但是,我不知道列表中的最后一个单词,所以我不能确定。由您决定哪种解码最适合您。

您的文件有哪种编码?Python默认读取
UTF-8
。看起来像是编码问题em.@albert,显然该文件被编码为Mac OS罗马编码(见下面我的)+1对于使用chardet,虽然在本例中,我认为chardet对其发现没有100%的信心是正确的。它仍然是猜测。由于159809个字中只有9个是非ASCII字,即使编码不正确,也可能很容易获得较高的信心。如果您查看实际文件,您将看到使用Windows-1252 wi对其进行解码将产生以下9个非ASCII单词:安德烈、附件、奇图、形态伦塞尔、塞恩、法贝格、勒维·施特劳斯、右“内塔尔、佩昂。我觉得这似乎不正确!+1彻底,并说明准确确定使用了哪种8位编码是多么困难。
>>> with open('german.txt', encoding='cp850') as f:
...     for line in f:
...         # do things with line
>>> b'Andr\x82'.decode('cp1252')
'Andr‚'