2010-04-29 6 views
3

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

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

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

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

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

В соответствии с «od -h file» оскорбительным символом является «1d1c».

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

gzip.open('file.gz') 

С:

os.popen('zcat file.gz') 

Он отлично работает (и на самом деле, довольно быстро). Но я хотел бы знать, где я ошибаюсь.

+0

Трудно диагностировать, не зная, что виновный линия выглядит. Можете ли вы выяснить, какой номер строки он есть, а затем, может быть, разместите шестнадцатеричный дамп исходной строки в файле, используя что-то вроде 'xxd' (или с помощью vim вы можете использовать ctrl-a, чтобы найти шестнадцатеричный код символа). –

+0

Покажите нам, вывод из 'print repr (weird_special_characters)'. Когда вы открываете файл в vim, ЧТО верны? Пожалуйста, уточните, чем «отформатировано странно». –

ответ

5

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

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'] 
+0

Какой изящный ответ! – chaimp

1

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

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

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

«Работает нормально с zcat» означает, что вы получили узнаваемые данные без шага дешифрования utf8?

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

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

Вот некоторые заметки о том, почему это происходит так:

В ASCII, только \ г и \ п считаются, когда линия отключающая:

>>> 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'] 
>>> 

Однако в Unicode, символы \ x1D (FILE SEPARATOR), \ x1e (GROUP SEPARATOR) и \ x1e (RECORD SEPARATOR) также квалифицируется как линии окончаний:

>>> 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 в файле.

+0

Я просматриваю несжатый файл (в частности, оскорбительную часть) с od. Вот где появляется «\ n». Я считаю, что это фактически 2-байтовый символ, который, если представлен как два отдельных байта, имеет «\ n». К сожалению, я не знаю, что такое исходная кодировка, но по какой-то причине vim и zcat представляют ее правильно, то есть они ее обнаруживают. – muckabout

+0

"Несжатый файл" ??? В вашем коде не отображается создание файла. Пожалуйста, покажите код, который вы фактически выполнили, создав файл, который вы изучаете с помощью 'od'. Пожалуйста, покажите шестнадцатеричный дамп из od, скажем, первые 100 байт файла. Пожалуйста, покажите шестнадцатеричный дамп от od, скажем, 100 байт, сосредоточенный на нарушающем '\ n '. Пожалуйста, покажите все это, отредактировав свой вопрос. –

+0

Сжатый файл - 10 ГБ. Проблема заключается не в первых 100 строках, а в непосредственной близости от 1-й линии. Я напечатал od od, который был, по-видимому, достаточно, чтобы понять проблему. Мой код не разжимает код, я делал это вручную диагностически. Мой код не создает файл, так что это тоже не имеет значения. Спасибо за предложение помочь, но вы можете быть менее боевыми. – muckabout