2013-03-19 5 views
0

Мне нужна помощь с циклом или лучший способ сделать это. Ответ может быть очевиден, но я новичок здесь и чувствую ментальный блок прямо сейчас: у меня есть файл журнала, который выглядит так, и я пытаюсь сопоставить все строки с тем же ID: поэтому я могу позже сравнить значения совпадающие идентификаторы. Я могу сопоставить первые строки, но тогда моя петля, кажется, заканчивается. Я не уверен, что я делаю неправильно, или вообще есть лучший подход. Любая помощь высоко ценится!Возврат всех совпадающих строк в файле журнала

Некоторые примечания:

  • , когда я разделить строки, столбец XYZ ID индексируется в строке [2], где Len (строка) == 11.
  • Я пытаюсь Переберите файл и для каждой строки создайте внутренний цикл, который сканирует оставшиеся строки файла, чтобы найти «соответствие».
  • Если совпадение найдено, я хочу вернуть это так, я могу сравнить значения
  • Беда мой код, кажется, перерыв после первого матча обнаруживается, что возвращает только первый матч нашел

ниже - мой код и образец файла журнала, с которым я работаю (включает некоторые отредактированные строки только для того, чтобы некоторые частные данные были закрыты). Фактическая файл_журнала включает запятые, которые были удалены, прежде чем я вставить в этот форум:

f = open('t.log','r') 
for line in f: 
    aline = line.replace(',','').split() 
    if len(aline)==11: 
     for line in f: 
      bline = line.replace(',','').split() 
      if len(bline)==11 and aline[2]==bline[2]: 
       print 'a: ', aline 
       print 'b: ', bline 

#t.log 

[13:40:19.xxx009] status -------    
[13:40:19.xxx013] status XYZ -4 -5675.36  quote 449.70/- 449.78 avg 1418.84 -7474.48  0.134  -55.630 -395.148  
[13:40:19.xxx021] status XYZ ID:22P00935xxx -4 3.92  quote: 0.98/ 1.02 avg: -0.98 -0.16 
[13:40:19.xxx024] status XYZ ID:22C0099xxx0 -2 26.4  quote: 11.60/ 11.85 avg: -13.20 2.70 
[13:40:19.xxx027] status XYZ ID:22P0099xxx0 10 -17.18 quote: 1.86/ 1.90 avg: -1.72 1.42 
[13:40:19.xxx029] status XYZ ID:22C00995xxx 4 -42.5 quote: 8.20/ 8.30 avg: -10.62 -9.70 
[13:40:19.xxx031] status XYZ ID:22P00995xxx 2 9.66  quote: 3.30/ 3.40 avg: 4.83 16.26 
[13:40:19.xxx535] status total xx5.52     

[13:41:20.xxx688] status -------    
[13:41:20.xxx691] status XYZ -4 -5675.36  quote 449.83/- 449.99 avg 1418.84 -7475.32  -0.374 -213.006  -39.391  
[13:41:20.xxx701] status XYZ ID:22P00935xxx -4 3.92  quote: 0.96/ 1.00 avg: -0.98 -0.08 
[13:41:20.xxx704] status XYZ ID:22C0099xxx0 -2 26.4  quote: 11.65/ 11.90 avg: -13.20 2.60 
[13:41:20.xxx708] status XYZ ID:22P0099xxx0 10 -17.18 quote: 1.83/ 1.87 avg: -1.72 1.12 
[13:41:20.xxx712] status XYZ ID:22C00995xxx 4 -42.5 quote: 8.20/ 8.30 avg: -10.62 -9.70 
[13:41:20.xxx716] status XYZ ID:22P00995xxx 2 9.66  quote: 3.30/ 3.35 avg: 4.83 16.26 
[13:41:20.xxx718] status XYZ ID:22C0095xxx0 -10 35.6  quote: 5.40/ 5.50 avg: -3.56 -19.40 
[13:41:20.001362] status total xx6.68  

Result:  
$ python pnlcomp.py 
    a: ['[13:40:19.000021]', 'statusAAPL', '130322P00435000', '-4', '3.92', 'quote:', '0.98/', '1.02', 'avg:', '-0.98', '-0.16'] 
    b: ['[13:41:20.000701]', 'statusAAPL', '130322P00435000', '-4', '3.92', 'quote:', '0.96/', '1.00', 'avg:', '-0.98', '-0.08'] 
+2

вы не можете использовать 'для линии в f' дважды в одном цикле –

+0

** ааа, спасибо ** – teachamantofish

+0

либо это не ваш фактический код, или это не фактическая Пример данных. Строки в 't.log' имеют 12 столбцов, а не 11, и ни один из них не имеет значений, близких к вашему выводу ... – abarnert

ответ

1

вы, вероятно, следует использовать регулярные выражения (также называемые регулярные выражения) для этого. Python имеет модуль re, который реализует регулярное выражение для python.

См. Это в качестве примера для направления взгляда: stackoverflow question finding multiple matches in a string.

Выписка из приведенного выше: Logfile выглядит следующим образом:

[1242248375] SERVICE ALERT: myhostname.com;DNS: Recursive;CRITICAL 

регулярное выражение выглядит следующим образом:

regexp = re.compile(r'\[(\d+)\] SERVICE NOTIFICATION: (.+)') 

, который выглядит следующим образом:

  • г => сырец строка (все дни рекомендуется в регулярных выражениях)
  • \ [=> соответствует квадратная скобка (которая в противном случае была бы специальным символом)
  • (\ d +) => соответствует одному или нескольким десятичным знакам \ d = десятичным знакам и + для 1 или более
  • \] =>, за которым следует закрывающая квадратная скобка
  • СЕРВИСНОЕ УВЕДОМЛЕНИЕ: => точно соответствует этим символам.
  • (. +) =>. (точка) соответствует любому символу. И снова + означает 1 или более

Скобки группируют результаты.

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

import re 
regexp = re.compile(r'\[(\d{2}:\d{2}:\d{2}\.xxx\d{3})\][\s]+status[\s]+XYZ[\s]+ID:([0-9A-Zx]+)(.+)') 

f = open("log.txt", "r") 
for line in f.readlines(): 
    print line 
    m = re.match(regexp, line) 
    #print m 
    if m: 
     print m.groups() 

Регулярные выражения не так просто смотреть или просто на первый взгляд, но если вы ищете регулярное выражение или ВЭ и питона вы найдете полезные примеры.

Outpus это для меня:

[13:40:19.xxx021] status XYZ ID:22P00935xxx -4 3.92  quote: 0.98/ 1.02 avg: -0.98 -0.16 

('13:40:19.xxx021', '22P00935xxx', ' -4 3.92  quote: 0.98/ 1.02 avg: -0.98 -0.16') 
[13:40:19.xxx024] status XYZ ID:22C0099xxx0 -2 26.4  quote: 11.60/ 11.85 avg: -13.20 2.70 

('13:40:19.xxx024', '22C0099xxx0', ' -2 26.4  quote: 11.60/ 11.85 avg: -13.20 2.70') 
[13:40:19.xxx027] status XYZ ID:22P0099xxx0 10 -17.18 quote: 1.86/ 1.90 avg: -1.72 1.42 

('13:40:19.xxx027', '22P0099xxx0', ' 10 -17.18 quote: 1.86/ 1.90 avg: -1.72 1.42') 
[13:40:19.xxx029] status XYZ ID:22C00995xxx 4 -42.5 quote: 8.20/ 8.30 avg: -10.62 -9.70 

('13:40:19.xxx029', '22C00995xxx', ' 4 -42.5 quote: 8.20/ 8.30 avg: -10.62 -9.70') 
[13:40:19.xxx031] status XYZ ID:22P00995xxx 2 9.66  quote: 3.30/ 3.40 avg: 4.83 16.26 
('13:40:19.xxx031', '22P00995xxx', ' 2 9.66  quote: 3.30/ 3.40 avg: 4.83 16.26') 

Каждая вторая линия является выход, который представляет собой список, содержащий совпавшие группы.

Если добавить это к вышеупомянутой программе:

print "ID is : ", m.groups()[1] 

выхода равен:

[13:40:19.xxx021] status XYZ ID:22P00935xxx -4 3.92  quote: 0.98/ 1.02 avg: -0.98 -0.16 

ID is : 22P00935xxx 

[13:40:19.xxx024] status XYZ ID:22C0099xxx0 -2 26.4  quote: 11.60/ 11.85 avg: -13.20 2.70 

ID is : 22C0099xxx0 

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

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

импорта повторно регулярных выражений = re.compile (г '[ (\ d {2}: \ д {2}: \ д {2} .xxx \ д {3})] [\ s] + статус [\ s] + XYZ [\ s] + ID: ([0- 9А-Zx] +) (. +) ')

res = {} 

f = open("log.txt", "r") 
for line in f.readlines(): 
    print line 
    m = re.match(regexp, line) 
    if m: 
     print m.groups() 
     id = m.groups()[1] 
     if id in res: 
      #print "added to existing ID" 
      res[id].append([m.groups()[0], m.groups()[2]]) 
     else: 
      #print "new ID" 
      res[id] = [m.groups()[0], m.groups()[2]] 

for id in res: 
    print "ID: ", id 
    print res[id] 

Теперь вы можете играть вокруг и тонкой настройки его, чтобы адаптировать его к вашим потребностям.

+0

Спасибо. Я пробовал это, но я получил эту ошибку: – teachamantofish

+0

Traceback (последний последний звонок): Файл «pnlcompregex.py», строка 9, в? print m.groups() AttributeError: объект «NoneType» не имеет атрибутных «групп» – teachamantofish

+0

это может быть потому, что я использую Python 2.4? – teachamantofish

1

Вы можете использовать функцию фильтра, чтобы получить какую-либо строку с «ID» в нем.

file = open('t.log', 'r') 
result = filter(lambda s: "ID" in s, file) 

Вы также можете использовать список понимание:

file = open('t.log', 'r') 
result = [s for s in file if 'ID' in s] 
+1

Я не думаю, что вы можете использовать 'with ... as' в Python 2.4. – squiguy

+0

Да, поскольку ['' with' Statement] (http://docs.python.org/2/reference/compound_stmts.html#with) говорит, что это новое в 2.5. (И требуется даже утверждение '__future__'.) – abarnert

+0

Ах да, мой плохой. Просто обновил его. – aikbix

0

Это, вероятно, не самый лучший способ, чтобы решить вашу проблему, но если вы хотите знать, как заставить его работать:

Проблема здесь в том, что ваш внутренний for line in f: цикл потребляет весь остальной Файл- поэтому, когда вы возвращаетесь во внешний цикл, читать нечего. (Там есть вторая проблема: Когда я запускаю свой код на данных, len(aline) всегда , не Но это тривиально исправить.).

Это не относится к файлам; так все итераторы работают на Python. Существует два общих способа решения этого вопроса для любого итератора, а также одно решение для конкретного файла.

Во-первых, есть itertools.tee. Это занимает итератор, и возвращает два итератора, каждый из которых может быть расширен независимо. Под одеялом, он, очевидно, должен использовать некоторые хранения для обработки вещей, если они не синхронизированы, поэтому документация говорит это:

In general, if one iterator uses most or all of the data before another iterator starts, it is faster to use list() instead of tee().

И вот другой вариант: Прочитайте весь итератор в list, поэтому вы можете перебирать фрагменты.

Это, очевидно, один из тех случаев, когда один итератор использует большую часть данных, а другой сидит в ожидании. Например, первый раз во внутреннем цикле вы читаете строки 1-20000, прежде чем внешний цикл прочитает строку 1. Итак, здесь лучше выбрать list.Итак:

f = open('t.log','r') 
contents = list(f) 
f.close() 
for idx, line in enumerate(contents): 
    aline = line.replace(',','').split() 
    if len(aline)==11: 
     for line in contents[idx+1:]: 
      bline = line.replace(',','').split() 
      if len(bline)==11 and aline[2]==bline[2]: 
       print 'a: ', aline 
       print 'b: ', bline 

Наконец, если у вас есть фантазии итератор, который может быть возобновлена ​​и контрольная точка в некотором роде, вы можете контрольную точку его прямо перед внутренним контуром, а затем возобновить его сразу после. И, к счастью, файлы имеют такую ​​вещь: tell возвращает текущую позицию файла, а seek переходит к указанной позиции. (Там большое предупреждение о том, что но это нормально «Если файл открыт в текстовом режиме (без 'b'), только смещения, возвращенные tell() законны.», Вы используете только смещение, возвращенные tell здесь.)

Итак:

f = open('t.log','r') 
for line in f: 
    aline = line.replace(',','').split() 
    if len(aline)==11: 
     pos = f.tell() 
     for line in f: 
      bline = line.replace(',','').split() 
      if len(bline)==11 and aline[2]==bline[2]: 
       print 'a: ', aline 
       print 'b: ', bline 
     f.seek(pos) 
+0

abarnert, что это делает ?: для строки в содержимом [idx + 1:]: – teachamantofish

+0

Кстати, ваш код, похоже, проделал для меня работу, но я все еще пытаюсь понять, почему это работает – teachamantofish

+0

пока что я думаю, что я может сказать, что содержимое [idx + 1:] возвращает список, начинающийся со следующей строки (элемента) в списке и заканчивающийся в конце списка. Итак, во внешней части цикла мы ищем alines с len == 11. Когда мы находим один из них, мы знаем его индекс из-за функции перечисления. Затем мы переходим к внутреннему циклу через «содержимое», где в качестве начальной точки мы используем индекс + 1 (это позволяет нам сканировать новые потенциальные совпадения («блины») без сканирования по уже отсканированным элементам).Наконец, я вижу, что мы проверяем соответствие строк и строк b, а затем печатаем, если true – teachamantofish

Смежные вопросы