Чтение файла с Python 3.6 - PullRequest
3 голосов
/ 29 июня 2019

Здравствуйте, я работаю с книгой Орейли Аллена Дауни для изучения Python3.x.В главе 9 приведен пример работы со списком слов в файле из проекта Moby.

https://en.wikipedia.org/wiki/Moby_Project

https://web.archive.org/web/20170930060409/http://icon.shef.ac.uk/Moby/

Я прочиталфайл german.txt со следующими строками Python.

with open("german.txt") as log:
        for line in log:
                word = line.strip()
                if len(word) > 20:
                        print(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

Какой символ имеется в виду?Как я могу справиться с этим с помощью кода Python.

Спасибо

Ответы [ 3 ]

1 голос
/ 29 июня 2019

В соответствии с документацией open():

, если кодировка не указана, используемое кодирование зависит от платформы: locale.getpreferredencoding (False) вызывается для получениятекущая кодировка локали.

То, как файл будет читаться, у всех разное.Чтобы гарантировать, что файл прочитан правильно , вам необходимо указать правильную кодировку .

В соответствии с документацией Проекта Moby в Википедии , «некоторые не-ASCII»остаются акцентированные символы, представленные в кодировке Mac OS Roman".В документации модуля Python codecs вы можете найти правильное имя для этого кодека, которое называется mac_roman.Таким образом, вы можете использовать следующий код, который не приводит к ошибке декодирования:

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

UPDATE

Несмотря на документацию, файл, похоже, небыть закодирован с использованием Mac OS римской кодировки.Я расшифровал файл, используя все возможные кодировки и сравнил результаты.В списке всего 9 не-ASCII слов, и слово «Андре» кажется правильным, как указано в другом ответе.Ниже приведен список возможных кодировок (которые не были ошибочными и включали слово «Андре») и 9 не-ASCII слов, декодированных в соответствии с этой кодировкой:

encodings: cp437, cp860, cp861, cp863, cp865
words: André, Attaché, Château, Conférencier, Cézanne, Fabergé, Lévi-Strauss, Rhônetal, p≥ange

encodings: cp720
words: André, Attaché, Château, Conférencier, Cézanne, Fabergé, Lévi-Strauss, Rhônetal, pٌange

encodings: cp775
words: André, Attaché, Chāteau, Conférencier, Cézanne, Fabergé, Lévi-Strauss, Rhōnetal, p“ange

encodings: cp850, cp858
words: André, Attaché, Château, Conférencier, Cézanne, Fabergé, Lévi-Strauss, Rhônetal, p‗ange

encodings: cp852
words: André, Attaché, Château, Conférencier, Cézanne, Fabergé, Lévi-Strauss, Rhônetal, p˛ange

Для всех вышеупомянутыхкодировки, первые 8 слов одинаковы при декодировании.Только для последнего слова есть 9 различных результатов.

На основании этих результатов я думаю , что использовалась кодировка cp720 .Однако я не узнаю последнее слово из списка, поэтому не могу сказать наверняка.Вам решать, какое декодирование наиболее подходит для вас.

0 голосов
/ 29 июня 2019

Угадать правильную кодировку для файла может быть сложно. Давайте начнем с открытия файла в двоичном режиме, поиска ошибочного байта и проверки окружающих символов.

>>> 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), мы можем увидеть, каким символам он может соответствовать. Я думаю, что наиболее вероятным совпадением является «é», давая нам правильное имя «Андре». Перекрестная проверка по списку кодировок Python , наиболее подходящей кодировкой является 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‚'
0 голосов
/ 29 июня 2019

Согласно моему комментарию выше, это похоже на проблему с кодировкой, которая, после тестирования, в значительной степени имеет место.

Обнаружение кодировки с помощью модуля chardet дает:

{'encoding': 'Windows-1252', 'confidence': 0.73, 'language': ''}

Что не является кодировкой Python по умолчанию UTF8. Чтобы читать файлы с другими кодировками, вам нужно указать желаемую кодировку при чтении файла, используя параметр encoding= функции open(filename, mode, encoding, ...).

Поскольку кодировка может быть неизвестна заранее, весьма удобно использовать UniversalDetector chardet , чтобы определить кодировку файла и затем передать его в файл, читая так:

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. Мои локали:

LANG="de_DE.UTF-8"
LC_COLLATE="de_DE.UTF-8"
LC_CTYPE="de_DE.UTF-8"
LC_MESSAGES="de_DE.UTF-8"
LC_MONETARY="de_DE.UTF-8"
LC_NUMERIC="de_DE.UTF-8"
LC_TIME="de_DE.UTF-8"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...