Справка по инверсному совпадению в Python

Здравствуйте! Я хочу обрезать файл журнала McAfee и удалить все сообщения "все в порядке" и другие зарегистрированные случаи, которые мне не интересно просматривать. Раньше мы использовали сценарий оболочки, который использовал опцию -v для grep, но теперь мы собираемся написать сценарий на python, который будет работать как в Linux, так и в Windows. После нескольких попыток я смог заставить регулярное выражение работать в онлайн-построителе регулярных выражений, но мне трудно внедрить его в мой сценарий. Онлайн REGEX Builder

Редактировать: я хочу удалить строки "все в порядке", "это ломаная", "это строки блока" и "файл не может быть открыт", так что я просто остаюсь с файлом только проблем, которые у меня есть Интересует. Вроде как в оболочке:

grep -v "is OK" ${OUTDIR}/${OUTFILE} | grep -v "is a broken" | grep -v "file could not be opened" | grep -v "is a block" > ${OUTDIR}/${OUTFILE}.trimmed 2>&1

Я читаю и ищу файл здесь:

import re

f2 = open(outFilePath)
contents = f2.read()
print contents
p = re.compile("^((?!(is OK)|(file could not be opened)| (is a broken)|(is a block)))*$", re.MULTILINE | re.DOTALL)
m = p.findall(contents)
print len(m)
for iter in m:
    print iter
f2.close()

Пример файла, который я пытаюсь найти:

eth0
10.0.11.196
00:0C:29:AF:6A:A7
parameters passed to uvscan: --DRIVER /opt/McAfee/uvscan/datfiles/current --    ANALYZE --AFC=32 ATIME-PRESERVE --PLAD --RPTALL RPTOBJECTS SUMMARY --UNZIP -- RECURSIVE --SHOWCOMP --MIME --THREADS=4 /tmp
temp XML output is: /tmp/HIQZRq7t2R
McAfee VirusScan Command Line for Linux64 Version: 6.0.5.614
Copyright (C) 2014 McAfee, Inc.
(408) 988-3832 LICENSED COPY - April 03 2016

AV Engine version: 5700.7163 for Linux64.
Dat set version: 8124 created Apr 3 2016
Scanning for 670707 viruses, trojans and variants.


No file or directory found matching /root/SVN/swd-lhn-build/trunk/utils/ATIME-PRESERVE

No file or directory found matching /root/SVN/swd-lhn-build/trunk/utils/RPTOBJECTS

No file or directory found matching /root/SVN/swd-lhn-build/trunk/utils/SUMMARY
/tmp/tmp.BQshVRSiBo ... is OK.
/tmp/keyring-F6vVGf/socket ... file could not be opened.
/tmp/keyring-F6vVGf/socket.ssh ... file could not be opened.
/tmp/keyring-F6vVGf/socket.pkcs11 ... file could not be opened.
/tmp/yum.log ... is OK.
/tmp/tmp.oW75zGUh4S ... is OK.
/tmp/.X11-unix/X0 ... file could not be opened.
/tmp/tmp.LCZ9Ji6OLs ... is OK.
/tmp/tmp.QdAt1TNQSH ... is OK.
/tmp/ks-script-MqIN9F ... is OK.
/tmp/tmp.mHXPvYeKjb/mcupgrade.conf ... is OK.
/tmp/tmp.mHXPvYeKjb/uvscan/uninstall-uvscan ... is OK.
/tmp/tmp.mHXPvYeKjb/mcscan ... is OK.
/tmp/tmp.mHXPvYeKjb/uvscan/install-uvscan ... is OK.
/tmp/tmp.mHXPvYeKjb/uvscan/readme.txt ... is OK.
/tmp/tmp.mHXPvYeKjb/uvscan/uvscan_secure ... is OK.
/tmp/tmp.mHXPvYeKjb/uvscan/signlic.txt ... is OK.
/tmp/tmp.mHXPvYeKjb/uvscan/uvscan ... is OK.
/tmp/tmp.mHXPvYeKjb/uvscan/liblnxfv.so.4 ... is OK.

Но я не получаю правильный вывод. Я попытался удалить опции MULTILINE и DOTALL, но все еще не получил правильный ответ. Ниже приведен вывод при работе с DOTALL и MULTILINE.

9
('', '', '', '', '')
('', '', '', '', '')
('', '', '', '', '')
('', '', '', '', '')
('', '', '', '', '')
('', '', '', '', '')
('', '', '', '', '')
('', '', '', '', '')
('', '', '', '', '')

Любая помощь приветствуется!! Спасибо!!

3 ответа

Решение

Возможно, подумайте проще, строка за строкой:

import re
import sys

pattern = re.compile(r"(is OK)|(file could not be opened)|(is a broken)|(is a block)")

with open(sys.argv[1]) as handle:
    for line in handle:
        if not pattern.search(line):
            sys.stdout.write(line)

Выходы:

eth0
10.0.11.196
00:0C:29:AF:6A:A7
parameters passed to uvscan: --DRIVER /opt/McAfee/uvscan/datfiles/current --    ANALYZE --AFC=32 ATIME-PRESERVE --PLAD --RPTALL RPTOBJECTS SUMMARY --UNZIP -- RECURSIVE --SHOWCOMP --MIME --THREADS=4 /tmp
temp XML output is: /tmp/HIQZRq7t2R
McAfee VirusScan Command Line for Linux64 Version: 6.0.5.614
Copyright (C) 2014 McAfee, Inc.
(408) 988-3832 LICENSED COPY - April 03 2016

AV Engine version: 5700.7163 for Linux64.
Dat set version: 8124 created Apr 3 2016
Scanning for 670707 viruses, trojans and variants.


No file or directory found matching /root/SVN/swd-lhn-build/trunk/utils/ATIME-PRESERVE

No file or directory found matching /root/SVN/swd-lhn-build/trunk/utils/RPTOBJECTS

No file or directory found matching /root/SVN/swd-lhn-build/trunk/utils/SUMMARY

Попробуйте это (и это делается в одну строку)

p = re.compile("^(?:[if](?!s OK|s a broken|s a block|ile could not be opened)|[^if])*$")

Это означает, что если в строке у вас есть "i" или "f", за ним не может следовать упомянутый суффикс или это не "i" или "f", тогда это нормально. Это повторяет это для всех персонажей в линии.

Изменить: После тестирования на regex101.com я обнаружил, почему он не работает. Вот регулярное выражение одной строки, которое будет работать.

p = re.compile("^(?:[^if\n]|[if](?!s OK|ile could not be openeds OK|s a broken|s a block|ile could not be opened))*$", re.MULTILINE)

Я знаю, что уже поздно отвечать. Но я вижу, что отсутствие ответа - правильное решение.

Ваше регулярное выражение для этого случая неверно. У вас есть ненужные дополнительные группы, отсутствует точка "." Кроме того, он будет соответствовать только в том случае, если "все в порядке | файл не может быть открыт | поврежден" в начале предложения.

"hello world is OK": does not match  
"is OK hello world": matches

В обратном совпадении просто используйте группу без захвата '(?:)' вместо группы захвата '()'. Это сделано для того, чтобы не получить пустую строку.

Если вы хотите удалить все предложение, вы можете использовать следующее выражение:

 r"^(?!.*(?:is OK|is a broken|file could not be opened)).*"
"is OK. hello world": matches  
"hello world is OK.": matches  
"is Ok.": matches

Если вы хотите удалить все предложение, но только те, которые оканчиваются на "в порядке.| Файл не может быть открыт.| Не работает.", Вы можете использовать следующее выражение:

r"^(?!.*(?:is OK|is a broken|file could not be opened)\.$).*"
"is OK. hello world" does not match  
"hello world is OK.": matches  
"is Ok.": matches

Не забудьте использовать группу без захвата '(?:)' вместо группы захвата '()', иначе вы получите пустую строку:

                #Capturing group
regex = r"^(?!.*(is OK|file could not be opened|is a broken|is a block)).*"
print(re.findall(regex,text,flags=re.MULTILINE))

вывод:

['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']

Используйте функцию join(), чтобы получить полный текст

                #Non-capturing group
regex = r"^(?!.*(?:is OK|file could not be opened|is a broken|is a block)).*"
print("\n".join(re.findall(regex,text,flags=re.MULTILINE)))

вывод:

eth1
10.0.11.196
00:0C:29:AF:6A:A7
parameters passed to uvscan: --DRIVER /opt/McAfee/uvscan/datfiles/current --    ANALYZE --AFC=32 ATIME-PRESERVE --PLAD --RPTALL RPTOBJECTS SUMMARY --UNZIP -- RECURSIVE --SHOWCOMP --MIME --THREADS=4 /tmp
temp XML output is: /tmp/HIQZRq7t2R
McAfee VirusScan Command Line for Linux64 Version: 6.0.5.614
Copyright (C) 2014 McAfee, Inc.
(408) 988-3832 LICENSED COPY - April 03 2016

AV Engine version: 5700.7163 for Linux64.
Dat set version: 8124 created Apr 3 2016
Scanning for 670707 viruses, trojans and variants.


No file or directory found matching /root/SVN/swd-lhn-build/trunk/utils/ATIME-PRESERVE

No file or directory found matching /root/SVN/swd-lhn-build/trunk/utils/RPTOBJECTS

No file or directory found matching /root/SVN/swd-lhn-build/trunk/utils/SUMMARY

Проверь это

Иногда регулярные выражения являются более сложными, но если вы действительно ищете только эти шаблоны, то я бы, вероятно, просто попробовал простой подход:

terms = (
    'is OK',
    'file could not be opened',
    'is a broken',
    'is a block',
)

with open('/tmp/sample.log') as f:
    for line in f:
        if line.strip() and not any(term in line for term in terms):
            print(line, end='')

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

terms = (
    'is a broken',
    'is a block',
)

with open('/tmp/samplelog.log') as f:
    for line in f:
        line = line.strip()
        if not line:
            continue
        elif line.endswith('is OK.'):
            continue
        elif line.endswith('file could not be opened.'):
            continue
        elif any(term in line for term in terms):
            continue
        print(line)

Подход, который я бы выбрал, во многом зависит от того, кого я ожидаю использовать в сценарии:)

Другие вопросы по тегам