Как собрать все строки данных между ключевыми словами в файле - начиная с + заканчивая переносом строк - PullRequest
0 голосов
/ 09 ноября 2018

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

Для справки пример журнала выглядит примерно так:

garbage I don't need - garbage I don't need
timestamp - date - server info - 'keyword 1' - data
more data more data more data more data
more data more data more data more data
more data more data 'keyword 2' - last bit of data
garbage I don't need - garbage I don't need

Мне нужно найти «ключевое слово 1», захватить всю строку, ключевое слово 1 включено (вернуться к отметке времени) и все последующие строки до (и включая) всей строки, в которой включено «ключевое слово 2» (до последнего немного данных).

Пока что я попробовал несколько вещей. Я не могу получить приличные результаты с помощью методов re (findall, match, search и т. Д.); Я не могу понять, как получить данные перед совпадением (даже с оглядкой назад), но что более важно, я не могу понять, как сделать так, чтобы захват остановился на фразе, а не на одном символе.

for match in re.findall('keyword1[keyword2]+|', showall.read()):

Я тоже пробовал что-то вроде этого:

start_capture = False
for current_line in fileName:
    if 'keyword1' in current_line:
        start_capture = True
    if start_capture:
        new_list.append(current_line)
    if 'keyword2' in current_line:
        return(new_list)

Независимо от того, что я пытался, это вернуло пустой список

Наконец, я попробовал что-то вроде этого:

def takewhile_plus_next(predicate, xs):
for x in xs:
    if not predicate(x):
        break
    yield x
yield x
with lastdb as f:
    lines = map(str.rstrip, f)
    skipped = dropwhile(lambda line: 'Warning: fatal assert' not in line, lines)
    lines_to_keep = takewhile_plus_next(lambda line: 'uptime:' not in line, skipped)

В этом последнем документе все содержалось от ключевого слова 1 до EOF, которое включает почти 100 000 строк данных для мусора.

Ответы [ 3 ]

0 голосов
/ 09 ноября 2018

Следующее быстро для любого размера файла. Он извлекает из 250-миллиметрового файла журнала почти 2 миллиона строк за 3 секунды. Извлеченная часть была в конце файла.

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

Тестовый текстовый файл startstop_text:

line 1 this should not appear in output
line 2 keyword1
line 3 appears in output
line 4 keyword2
line 5 this should not appear in output

Код:

from itertools import dropwhile


def keepuntil(contains_end_keyword, lines):
    for line in lines:
        yield line
        if contains_end_keyword(line):
            break


with open('startstop_text', 'r') as f:
    from_start_line = dropwhile(lambda line: 'keyword1' not in line, f)
    extracted = keepuntil(lambda line: 'keyword2' in line, from_start_line)
    for line in extracted:
        print(line.rstrip())


>>> python startstop.py
line 2 keyword1
line 3 appears in output
line 4 keyword2
0 голосов
/ 11 ноября 2018

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

for match in re.findall(".*keyword1[\s\S]*?keyword2:[\s\S]*?keyword3.*", log_file.read()):
0 голосов
/ 09 ноября 2018

Вы можете использовать регулярное выражение, если вы укажете re.dotall и будете использовать ленивое. *? чтобы соответствовать началу и концу:

import re

regex = r"\n.*?(keyword 1).*?(keyword 2).*?$"

test_str = ("garbage I don't need - garbage I don't need\n"
    "timestamp - date - server info - 'keyword 1' - data\n"
    "more data more data more data more data\n"
    "more data more data more data more data\n"
    "more data more data 'keyword 2' - last bit of data\n"
    "garbage I don't need - garbage I don't need")

matches = re.finditer(regex, test_str, re.DOTALL | re.MULTILINE)

for matchNum, match in enumerate(matches):
    matchNum = matchNum + 1

    print (match.group()) # your match is the whole group

Выход:

timestamp - date - server info - 'keyword 1' - data 
more data more data more data more data
more data more data more data more data
more data more data 'keyword 2' - last bit of data

Вам может понадобиться strip('\n') из него ...

Вы можете посмотреть его здесь: https://regex101.com/r/HWIALZ/1 - он также содержит объяснение скороговорки. Короче говоря:

\n        newline 
   .*?    as few as possible anythings
   (keyword 1)   literal text - the () are not needed only if you want the group
   .*?    as few as possible anythings
   (keyword 2)   literal text - again () are not needed 
   .*?    as few as possible anythings
$         end of line

Я включил () для ясности - вы не оцениваете группы, вы их удаляете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...