#python
#python
Вопрос:
Привет, у меня есть довольно большой файл, который я хочу обработать с помощью Python, и я немного застрял в том, как это сделать.
Формат моего файла такой:
0 ххх хххх хххх ххххххххххххххххххххххххххххххххххххххххххххххххххххххххххххххххххххххх xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
1 ххх хххх хххх ххххххххххххххххххххххххххххххххххххххххххххххххххххххххххххххххххххххх xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Итак, я в основном хочу прочитать фрагмент от 0-1, выполнить свою обработку над ним, затем перейти к фрагменту между 1 и 2.
До сих пор я пытался использовать регулярное выражение для сопоставления числа, а затем продолжать итерацию, но я уверен, что должен быть лучший способ сделать это. Любые предложения / информация будут высоко оценены.
Комментарии:
1. Что не так с техникой регулярных выражений? Это довольно распространенное явление. Пожалуйста, опубликуйте код.
2. Вот пример из neopythonic neopythonic.blogspot.in/2008/10 /…
Ответ №1:
Если все они находятся в пределах одной строки, то есть между «1» и «2» нет разрывов строк. Тогда вы можете выполнить итерацию по строкам файла следующим образом:
for line in open("myfile.txt"):
#do stuff
Строка будет удаляться и перезаписываться на каждой итерации, что означает, что вы можете легко обрабатывать файлы больших размеров. Если они не находятся в одной строке:
for line in open("myfile.txt"):
if #regex to match start of new string
parsed_line = line
else:
parsed_line = line
и остальной части вашего кода.
Комментарии:
1. Я поставил 1. Однако это содержит несколько сложных случаев, поскольку это связано с тем, что конечное условие становится известным только тогда, когда была прочитана следующая строка данных (строка начинается с «N»). В этом случае последняя прочитанная строка должна использоваться в качестве первых данных следующего элемента. (На самом деле, я думаю, что простое указание на сайтах вызовов того, где
parsed_line
фактически используется, прояснило бы этот порядок записи; в зависимости от этого есть несколько крайних случаев).2. @pst хороший улов. Теперь, когда вы указали на них, есть крайние случаи.
Ответ №2:
Почему бы вам просто не прочитать файл по порядку, используя file.read(1)
символ за символом?
Затем вы могли бы — на каждой итерации — проверять, пришли ли вы к символу 1
. Затем вы должны убедиться, что сохранение строки происходит быстро.
Ответ №3:
Если буква «N» может только начинать строку, то почему бы не использовать «простое» решение? (Похоже, что это уже делается, я пытаюсь усилить / поддержать это;-))
То есть, просто считываете строку за раз и создаете данные, представляющие текущий N объект. Скажем, после загрузки N = 0 и N = 1 обработайте их вместе, затем переходите к следующей паре (N = 2, N = 3). Единственное, что даже отдаленно сложно, это убедиться, что не выбрасывается прочитанная строка. (Прочитанная строка, которая определяет конечное условие — например, «N» — также содержит данные для следующего N).
Если поиск не требуется (или кэширование ввода-вывода отключено, или на элемент приходится абсурдное количество данных), на самом деле нет причин не использовать readline AFAIK.
Удачного кодирования.
Вот некоторый нестандартный код, который, вероятно, содержит множество ошибок. В любом случае, это показывает общую идею с использованием минимизированного подхода к побочным эффектам.
# given an input and previous item data, return either
# [item_number, data, next_overflow] if another item is read
# or None if there are no more items
def read_item (inp, overflow):
data = overflow or ""
# this can be replaced with any method to "read the header"
# the regex is just "the easiest". the contract is just:
# given "N ....", return N. given anything else, return None
def get_num(d):
m = re.match(r"(d ) ", d)
return int(m.groups(1)) if m else None
for line in inp:
if data and get_num(line) ne None:
# already in an item (have data); current line "overflows".
# item number is still at start of current data
return [get_num(data), data, line]
# not in item, or new item not found yet
data = line
# and end of input, with data. only returns above
# if a "new" item was encountered; this covers case of
# no more items (or no items at all)
if data:
return [get_num(data), data, None]
else
return None
И использование может быть сродни следующему, где f
представляет открытый файл:
# check for error conditions (e.g. None returned)
# note feed-through of "overflow"
num1, data1, overflow = read_item(f, None)
num2, data2, overflow = read_item(f, overflow)
Ответ №4:
Если формат фиксирован, почему бы просто не читать по 3 строки за раз с помощью readline()
Комментарии:
1. Это не исправлено, хотя я полагаю, что мой пост подразумевал это. Между числами может быть любое количество строк.
2. Итак, вы хотите прочитать до строки, начинающейся с числа? нет ли вероятности, что текст в xxxxxx-х может содержать число, которое можно перенести на новую строку? разделены ли строки?
3. Да, ххх могут быть числами, но первые числа для каждой записи являются последовательными, поэтому 1 .. n. Запись разделяется символом n перед следующим порядковым номером.
4. Может ли весь файл поместиться в памяти?
Ответ №5:
Если файл маленький, вы можете прочитать весь файл и разделить () на числовые цифры (возможно, захотите использовать strip(), чтобы избавиться от пробелов и новых строк), затем свернуть список, чтобы обработать каждую строку в списке. Вероятно, вам придется проверить, что результирующая строка, которую вы обрабатываете, изначально не пуста, в случае, если две цифры были рядом друг с другом.
Комментарии:
1. Если вы ищете числа только в начале строк, то вам, вероятно, не следует разделять (на самом деле я не уверен, что разделять вообще полезно для вас), а вместо этого выполнить разделение для комбинации цифр новой строки с помощью регулярных выражений split: [ссылка] docs.python.org/library/re.html#re.split
2. Файл является массивным (около 1,2 ГБ).
3. Если вы ищете набор чисел в начале строк в последовательном порядке… Тогда вам, вероятно, следует написать свою собственную функцию разделения, которая просто выполняет итерацию по строке и разбивает ее в нужное время… Поскольку это массивный файл, я думаю, что phimuemue прав: вы должны читать его посимвольно, и часть вашей обработки должна быть «это последовательность символов новой строки, которая является следующим разделителем?»
Ответ №6:
Если содержимое файла может быть загружено в память, и это то, что вы ответили, тогда следующий код (должно быть определено имя файла) может быть решением.
import re
regx = re.compile('^((d ).*?)(?=^d|Z)',re.DOTALL|re.MULTILINE)
with open(filename) as f:
text = f.read()
def treat(inp,regx=regx):
m1 = regx.search(inp)
numb,chunk = m1.group(2,1)
li = [chunk]
for mat in regx.finditer(inp,m1.end()):
n,ch = mat.group(2,1)
if int(n) == int(numb) 1:
yield ''.join(li)
numb = n
li = []
li.append(ch)
chunk = ch
yield ''.join(li)
for y in treat(text):
print repr(y)
Этот код выполняется в файле, содержащем :
1 mountain
orange 2
apple
produce
2 gas
solemn
enlightment
protectorate
3 grimace
song
4 snow
wheat
51 guludururu
kelemekinonoto
52asabi dabada
5 yellow
6 pink
music
air
7 guitar
blank 8
8 Canada
9 Rimini
создает:
'1 mountainnorange 2napplenproducen'
'2 gasnsolemnnenlightmentnprotectoraten'
'3 grimacensongn'
'4 snownwheatn51 guludururunkelemekinonoton52asabi dabadan'
'5 yellown'
'6 pink nmusicnairn'
'7 guitarnblank 8n'
'8 Canadan'
'9 Rimini'