python3: IP-Adresse aus kompiliertem Muster extrahieren

8

Ich möchte jede Zeile in meiner Protokolldatei verarbeiten und die IPAdresse extrahieren , wenn die Zeile meinem Muster entspricht. Es gibt verschiedene Arten von Nachrichten, im folgenden Beispiel verwende ich p1 andp2`.

Ich konnte die Datei Zeile für Zeile lesen und für jede Zeile mit jedem Muster übereinstimmen. Aber da es viel mehr Muster geben kann, möchte ich es so effizient wie möglich machen. Ich hatte gehofft, diese Muster zu einem Objekt zusammenzufassen und das Match nur einmal für jede Zeile durchzuführen:

import re

IP = r'(?P<ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'

p1 = 'Registration from' + IP + '- Wrong password' 
p2 = 'Call from' + IP + 'rejected because extension not found'

c = re.compile(r'(?:' + p1 + '|' + p2 + ')')

for line in sys.stdin:
    match = re.search(c, line)
    if match:
        print(match['ip'])

aber der obige Code funktioniert nicht, er beschwert sich, dass iper zweimal verwendet wird.

Was ist der eleganteste Weg, um mein Ziel zu erreichen?

BEARBEITEN:

Ich habe meinen Code basierend auf der Antwort von @Dev Khadka geändert.

Aber ich habe immer noch Probleme damit, wie ich mit den vielen ipSpielen richtig umgehen kann . Der folgende Code gibt alle IPs aus, die mit p1 übereinstimmen:

for line in sys.stdin:
    match = c.search(line)
    if match:
        print(match['ip1'])

Einige Zeilen stimmen jedoch nicht überein p1. Sie passen zusammen p2. dh ich bekomme:

1.2.3.4
None
2.3.4.5
...

Wie finde ich die passende IP drucken, wenn ich nicht weiß , wheter es war p1, p2...? Ich möchte nur die IP. Es ist mir egal, zu welchem ​​Muster es passt.

Martin Vegter
quelle
1
Sie sollten Ihre Testdaten angeben.
eyllanesc

Antworten:

4

Sie können das hervorragende regexModul installieren , das viele erweiterte Regex-Funktionen unterstützt, einschließlich Zweig-Reset-Gruppen , um genau das Problem zu lösen, das Sie in dieser Frage beschrieben haben. Verzweigungsrücksetzgruppen sind mit gekennzeichnet (?|...). Alle Erfassungsgruppen mit denselben Positionen oder Namen in unterschiedlichen alternativen Mustern innerhalb einer Gruppe zum Zurücksetzen von Zweigen verwenden dieselben Erfassungsgruppen für die Ausgabe.

Beachten Sie, dass im folgenden Beispiel die übereinstimmende Erfassungsgruppe zur benannten Erfassungsgruppe wird, sodass Sie nicht mehrere Gruppen durchlaufen müssen, um nach einer nicht leeren Gruppe zu suchen:

import regex

ip_pattern = r'(?P<ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
patterns = [
    'Registration from {ip} - Wrong password',
    'Call from {ip} rejected because extension not found'
]
pattern = regex.compile('(?|%s)' % '|'.join(patterns).format(ip=ip_pattern))
for line in sys.stdin:
    match = regex.search(pattern, line)
    if match:
        print(match['ip'])

Demo: https://repl.it/@blhsing/RegularEmbellishedBugs

blhsing
quelle
1
Dies ist perfekt! Vielen Dank.
Martin Vegter
2

Warum überprüfst du nicht, welcher Regex übereinstimmt?

if 'ip1' in match :
    print match['ip1']
if 'ip2' in match :
    print match['ip2']

oder so ähnlich wie:

names = [ 'ip1', 'ip2', 'ip3' ]
for n in names :
    if n in match :
        print match[n]

oder auch

num = 1000   # can easily handle millions of patterns =)
for i in range(num) :
    name = 'ip%d' % i
    if name in match :
        print match[name]
lenik
quelle
aber was ist, wenn ich 100 Muster habe? Kann ich das in einer Schleife machen? Kann ich über die match[i]in einer for-Schleife iterieren ?
Martin Vegter
@ MartinVegter siehe oben
Lenik
@ MartinVegter kann leicht mit Millionen von Mustern umgehen =)
Lenik
Ich erhalte eine Fehlermeldung:if match[name] is not None: IndexError: no such group
Martin Vegter
@ MartinVegter versuchen, name in matchstattdessen zu verwenden
Lenik
1

Das liegt daran, dass Sie denselben Gruppennamen für zwei Gruppen verwenden

Versuchen Sie dies, dies gibt die Gruppennamen ip1 und ip2

import re

IP = r'(?P<ip%d>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'

p1 = 'Registration from' + IP%1 + '- Wrong password' 
p2 = 'Call from' + IP%2 + 'rejected because extension not found'

c = re.compile(r'(?:' + p1 + '|' + p2 + ')')
Dev Khadka
quelle
1

Benannte Erfassungsgruppen müssen unterschiedliche Namen haben. Da jedoch alle Erfassungsgruppen dasselbe Muster erfassen sollen, ist es in diesem Fall besser, keine benannten Erfassungsgruppen zu verwenden, sondern einfach reguläre Erfassungsgruppen zu verwenden und die Gruppen vom Übereinstimmungsobjekt aus zu durchlaufen So drucken Sie die erste Gruppe, die nicht leer ist:

ip_pattern = r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'
patterns = [
    'Registration from {ip} - Wrong password',
    'Call from {ip} rejected because extension not found'
]
pattern = re.compile('|'.join(patterns).format(ip=ip_pattern))
for line in sys.stdin:
    match = re.search(pattern, line)
    if match:
        print(next(filter(None, match.groups())))

Demo: https://repl.it/@blhsing/UnevenCheerfulLight

blhsing
quelle