Итерация файла строки Python и странные символы - PullRequest
3 голосов
/ 29 апреля 2010

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

for i, line in enumerate(codecs.getreader('utf-8')(gzip.open('file.gz'))):
  print i, line

В какой-то момент в конце файла вывод Python отличается от файла. Это потому, что строки ломаются из-за странных специальных символов, которые Python считает новыми строками. Когда я открываю файл в 'vim', они корректны, но подозрительные символы странно отформатированы. Что я могу сделать, чтобы это исправить?

Я пробовал другие кодеки, включая utf-16, latin-1. Я также пытался без кодека.

Я посмотрел на файл, используя 'od'. Конечно же, есть символы \ n, где их не должно быть. Но «неправильным» предшествует странный характер. Я думаю, что здесь есть некоторая кодировка с некоторыми символами в 2 байта, но завершающий байт является \ n, если не просматривается должным образом.

В соответствии с 'od -h file', символ-нарушитель - '1d1c'.

Если я заменю:

gzip.open('file.gz')

С:

os.popen('zcat file.gz')

Работает нормально (и на самом деле, довольно быстро). Но я хотел бы знать, где я иду не так.

Ответы [ 2 ]

5 голосов
/ 02 мая 2010

Попробуйте еще раз без кодека.Следующее воспроизводит вашу проблему при использовании кодека и отсутствие проблемы без него:

import gzip 
import os 
import codecs 

data = gzip.open("file.gz", "wb") 
data.write('foo\x1d\x1cbar\nbaz') 
data.close() 

print list(codecs.getreader('utf-8')(gzip.open('file.gz'))) 
print list(os.popen('zcat file.gz')) 
print list(gzip.open('file.gz')) 

Выходы:

[u'foo\x1d', u'\x1c', u'bar\n', u'baz']
['foo\x1d\x1cbar\n', 'baz']
['foo\x1d\x1cbar\n', 'baz']
1 голос
/ 30 апреля 2010

Я спросил (в комментарии) "" "Покажите нам вывод из print repr (weird_special_characters). Когда вы открываете файл в vim, ЧТО правильно? Пожалуйста, будьте более точными, чем" странно отформатированный "." "" Но ничего: - (

Какой файл вы смотрите с od? file.gz ?? Если вы видите там что-то узнаваемое, это не файл gzip! Вы не видите новые строки, вы видите двоичные байты, которые содержат 0x0A.

Если исходный файл был закодирован в формате utf-8, какой смысл пытаться использовать его с другими кодеками?

Означает ли "работает нормально с zcat", что вы получили распознаваемые данные без шага декодирования utf8 ??

Я предлагаю вам упростить код и выполнять его шаг за шагом ... см., Например, принятый ответ на этот вопрос . Попробуйте еще раз и, пожалуйста, покажите точный код, который вы запустили, и используйте repr () при описании результатов.

Обновление Похоже, DS догадался, что вы пытались объяснить относительно \ x1c и \ x1d.

Вот некоторые заметки о том, ПОЧЕМУ это происходит так:

В ASCII только \ r и \ n учитываются при переносе строки:

>>> import pprint
>>> text = ''.join('A' + chr(i) for i in range(32)) + 'BBB'
>>> print repr(text)
'A\x00A\x01A\x02A\x03A\x04A\x05A\x06A\x07A\x08A\tA\nA\x0bA\x0cA\rA\x0eA\x0fA\x10
A\x11A\x12A\x13A\x14A\x15A\x16A\x17A\x18A\x19A\x1aA\x1bA\x1cA\x1dA\x1eA\x1fBBB'
>>> pprint.pprint(text.splitlines(True))
['A\x00A\x01A\x02A\x03A\x04A\x05A\x06A\x07A\x08A\tA\n', # line break
 'A\x0bA\x0cA\r', # line break
 'A\x0eA\x0fA\x10A\x11A\x12A\x13A\x14A\x15A\x16A\x17A\x18A\x19A\x1aA\x1bA\x1cA\x
1dA\x1eA\x1fBBB']
>>>

Однако в Юникоде символы \ x1D (РАЗДЕЛИТЕЛЬ ФАЙЛА), \ x1E (РАЗДЕЛИТЕЛЬ ГРУППЫ) и \ x1E (РАЗДЕЛИТЕЛЬ ЗАПИСИ) также квалифицируются как окончания строк:

>>> text = u''.join('A' + unichr(i) for i in range(32)) + u'BBB'
>>> print repr(text)
u'A\x00A\x01A\x02A\x03A\x04A\x05A\x06A\x07A\x08A\tA\nA\x0bA\x0cA\rA\x0eA\x0fA\x10A\x11A\x12A\x13A\x14A\x15A\x16A\x17A\x18A\x19A\x1aA\x1bA\x1cA\x1dA\x1eA\x1fBBB'
>>> pprint.pprint(text.splitlines(True))
[u'A\x00A\x01A\x02A\x03A\x04A\x05A\x06A\x07A\x08A\tA\n', # line break
 u'A\x0bA\x0cA\r', # line break
 u'A\x0eA\x0fA\x10A\x11A\x12A\x13A\x14A\x15A\x16A\x17A\x18A\x19A\x1aA\x1bA\x1c', # line break
 u'A\x1d', # line break
 u'A\x1e', # line break
 u'A\x1fBBB']
>>>

Это произойдет независимо от того, какой кодек вы используете. Вам все еще нужно решить, какой (если есть) кодек нужно использовать. Вам также необходимо выяснить, действительно ли исходный файл был текстовым, а не двоичным. Если это текстовый файл, вам необходимо учитывать значение \ x1c и \ x1d в этом файле.

...