2016-08-26 4 views
1
import re 

infile = open('document.txt','r') 
outfile= open('output.txt','w') 
copy = False 
for line in infile: 

    if line.strip() == "--operation():": 
     bucket = [] 
     copy = True 

    elif line.strip() == "StartOperation": 
     for strings in bucket: 
      outfile.write(strings + ',') 
     for strings in bucket: 
      outfile.write('\n') 
     copy = False 

    elif copy: 
     bucket.append(line.strip() 

формат CSV, как это:Python скрипт для поиска переменных строк между двумя постоянными строками

id,   name,    poid,   error 
5896, AutoAuthOSUserSubmit,  900105270,  0x4002 

Мой лог-файл состоит из нескольких разделов, начиная с ==== START ==== и заканчивая ==== END ====. Я хочу извлечь строку между --operation(): и StartOperation. Например, AutoAuthOSUserSubmit. Я также хочу извлечь значение poid из строки poid: 900105270, poidLen: 9. Наконец, я хочу извлечь возвращаемое значение, например 0x4002, если после него найдено Roll back all updates.

Я даже не могу извлечь исходный текст, если Start и End находятся не на одной линии. Как мне это сделать?

Это образец LOG экстракт с двумя пунктами:

-- 08/24 02:07:56 [mds.ecas(5896) ECAS_CP1] **==== START ====** 
open file /ecas/public/onsite-be/config/timer.conf failed 
INFO 08/24/16 02:07:56 salt1be-d1-ap(**5896**/0) main.c(780*****):--operation(): AutoAuthOSUserSubmit. StartOperation***** 
INFO 08/24/16 02:07:56 salt1be-d1-ap(5896/0) main.c(784):--Client Information: Request from host 'malt-d1-wb' process id 12382. 
DEBUG 08/24/16 02:07:56 salt1be-d1-ap(5896/0) TOci.cc(571):FetchServiceObjects: ServiceCert.sql 
DEBUG 08/22/16 23:15:53 pepper1be-d1-ap(2680/0) vsserviceagent.cpp(517):Generate Certificate 2: c1cd00d5c3de082360a08730fef9cd1d 
DEBUG 08/22/16 23:15:53 pepper1be-d1-ap(2680/0) junk.c(1373):GenerateWebPin : poid: **900105270**, poidLen: 9 
DEBUG 08/22/16 23:15:53 pepper1be-d1-ap(2680/0) junk.c(1408):GenerateWebPin : pinStr 
DEBUG 08/24/16 02:07:56 salt1be-d1-ap(5896/0) uaadapter_vasco_totp.c(275):UAVascoTOTPImpl.close() -- Releasing Adapter Context 
DEBUG 08/22/16 23:15:53 pepper1be-d1-ap(2680/0) vsenterprise.cpp(288):VSEnterprise::Engage returns 0x4002 - Unknown error code **(0x4002)** 
ERROR 08/22/16 23:15:53 pepper1be-d1-ap(2680/0) vsautoauth.cpp(696):OSAAEndUserEnroll: error occurred. **Roll back** all updates! 
INFO 08/24/16 02:07:56 salt1be-d1-ap(5896/0) uaotptokenstoreqmimpl.cpp(199):Close token store 
INFO 08/24/16 02:07:56 salt1be-d1-ap(5896/0) main.c(990):-- EndOperation 
-- 08/24 02:07:56 [mds.ecas(5896) ECAS_CP1] **==== END ====** 
    OPERATION = AutoAuthOSUserSubmit, rc = 0x0 (0) 
    SYSINFO Elapse = 0.687, Heap = 1334K, Stack = 64K 

ответ

1

Это выглядит как работа для регулярных выражений! Несколько на самом деле. К счастью, в этом случае они не очень сложны.

Есть 2 основных замечания, которые сделали бы мне выбрать регулярные выражения над чем-то еще:

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

Вы можете попробовать что-то вроде этого:

import re 

def capture(text, pattern_string, flags=0): 
    pattern = re.compile(pattern_string, flags) 
    match = pattern.search(text) 
    if match: 
     output = match.group(1) 
     print '{}\n'.format(output) 
     return output 
    return '' 

if __name__ == '__main__': 
    file = read_my_file() 

    log_pattern = "\*\*==== START ====\*\*(.+)\*\*==== END ====\*\*" 
    log_text = capture(file, log_pattern, flags=re.MULTILINE|re.DOTALL) 

    op_pattern = "--operation\(\): (.+). StartOperation\*\*\*\*\*" 
    op_name = capture(log_text, op_pattern) 

    poid_pattern = "poid: \*\*([\d]+)\*\*, poidLen: " 
    op_name = capture(log_text, poid_pattern) 

    retcode_pattern = "Unknown error code \*\*\((.+)\)\*\*.+\*\*Roll back\*\* all updates!" 
    retcode = capture(log_text, retcode_pattern, flags=re.MULTILINE|re.DOTALL) 

Этот подход существенно делит проблему на несколько значительных независимых шагов. Я использую группы захвата в каждом регулярном выражении - такие как (.+) и ([\d]+) - между длинными строками постоянных символов. Многострочные и точечные флаги позволяют легко обрабатывать разрывы строк в тексте и обрабатывать их так же, как и любую другую часть строки.

Я также делаю здесь большое предположение, и ваши журналы не являются огромными файлами, а может быть, несколькими сотнями мегабайт. Обратите внимание на вызов read_my_file() - вместо того, чтобы пытаться решить эту проблему по одной строке за раз, я решил прочитать весь файл и работать в памяти. Если файлы становятся действительно большими, или вы создаете приложение, которое получит большой трафик, это может быть плохой идеей.

Надеюсь, это поможет!

+0

Спасибо за руководство. У меня есть один большой файл журнала размером около 2 ГБ. Допустим, я просто хочу извлечь поле «имя» только, например. AutoAuthOSUserSubmit. Ошибка кода с ошибками. Можете ли вы просто дать проверенный код только для поля имени. В других областях я постараюсь разобраться. – Aryabhatta

+0

@ Исследуйте одну из причин, по которой это может быть неудачно, потому что я не определил 'read_my_file()' - это было намеренно, и вам лучше оставить вас, так как я не знаю, откуда ваши журналы. Кроме того, я использую python 2.7 - если вы используете 3, возможно, мой код не работает. Какая ошибка? Какая линия? 2GB может быть слишком большим для чтения в память в любом случае, и было бы неплохо сначала нарезать файл на более мелкие файлы как шаг предварительной обработки. – killthrush

+0

Кроме того, ваш журнал не может быть «постоянным», как вы думали. Много мусора может скрывать текст на 2 ГБ. – killthrush

1

Похоже, что вы просто пытаетесь найти строки в пределах LOG документа и пытаетесь разобрать строки символов с помощью ключевых слов. Вы можете пойти по очереди, что вы делаете в настоящее время, или вы можете пройти через документ один раз (при условии, что документ LOG никогда не станет огромным) и добавьте каждую последующую строку в существующую строку.

Проверить это для нахождения подстрок http://www.tutorialspoint.com/python/string_index.htm < --- для нахождения места, где строка находится в другой строке, это поможет вам определить индекс начального и конечный индекс. После этого вы сможете извлечь нужную вам информацию.

Проверить это для вашей проблемы CSV http://www.tutorialspoint.com/python/string_split.htm < --- для разбиения строки вокруг определенного символа т.е. «» для файлов CSV.

Does Python have a string contains substring method? будет более полезным, чем ваш метод с использованием метода

() полосу Надеюсь, это будет указывать вам в правильном направлении!