Seite 1 von 2

Regex-Gruppen

Verfasst: Sonntag 14. Mai 2017, 14:19
von Taadu
Ich bin mir nicht sicher, ob ich hier richtig bin, aber ich versuche es einfach mal. Ich habe mal eine Frage zu Regex, ich muss einen Apachelog nach bestimmten Vorgaben ana­ly­sie­ren lassen, dabei kann ich eine solche Beispielzeile aus der Datei: 172.16.11.12 - - [26/May/2013:14:06:05 +0200] \"GET /navleiste/d_szut_navleiste.gif HTTP/1.1\" 200 1776 mit Hilfe von (r"^(.*?) (.*?) (.*?) \[(.*?)\] \"(.*?) (.*?) (.*?)\" (.*?) (.*?)$") zumindest schonmal abdecken, jedoch weiß ich nicht genau, wie ich die einzelnen "Gruppen" in anderer Reihenfolge bzw. alleine abrufen kann. Möglicherweise mache etwas Grundlegend falsch oder übersehe etwas.
MfG.
Taadu

Re: Regex-Gruppen

Verfasst: Sonntag 14. Mai 2017, 14:54
von kbr
Möglicherweise suchst Du "named groups".

Re: Regex-Gruppen

Verfasst: Sonntag 14. Mai 2017, 15:56
von noisefloor
Hallo,

die Gruppen sind durchnummeriert und mit der `group()` Methode kannst du drauf zugreifen. Beispiel (Python 3.5):

Code: Alles auswählen

>>> my_string = '172.16.11.12 - - [26/May/2013:14:06:05 +0200] \"GET /navleiste/d_szut_navleiste.gif HTTP/1.1\" 200 1776'
>>> import re
>>> regex = r'^(.*?) (.*?) (.*?) \[(.*?)\] \"(.*?) (.*?) (.*?)\" (.*?) (.*?)$'
>>> p = re.compile(regex)
>>> m = p.match(my_string)
>>> m.group()
'172.16.11.12 - - [26/May/2013:14:06:05 +0200] "GET /navleiste/d_szut_navleiste.gif HTTP/1.1" 200 1776'
>>> m.group(0)
'172.16.11.12 - - [26/May/2013:14:06:05 +0200] "GET /navleiste/d_szut_navleiste.gif HTTP/1.1" 200 1776'
>>> m.group(1)
'172.16.11.12'
>>> m.group(5)
'GET'
>>> m.group(6)
'/navleiste/d_szut_navleiste.gif'
>>>
Mit `groups()` siehst du alle Capture-Gruppen:

[codebox=pycon file=Unbenannt.txt]>>> m.groups()
('172.16.11.12', '-', '-', '26/May/2013:14:06:05 +0200', 'GET', '/navleiste/d_szut_navleiste.gif', 'HTTP/1.1', '200', '1776')
>>>
[/code]

Gruß, noisefloor

Re: Regex-Gruppen

Verfasst: Sonntag 14. Mai 2017, 16:17
von Taadu
Vielen Dank für die Antworten, sie haben mir sehr weitergeholfen, ich werde das sobald wie möglich ausprobieren.
Ich war gerade dabei einen Beitrag zu verfassen, in dem ich um ein Beispiel bitte und noch davor wurde eines bereitgestellt.

Re: Regex-Gruppen

Verfasst: Sonntag 14. Mai 2017, 16:53
von beertonic
Hier ein Bsp. für named groups:

Code: Alles auswählen

r = '^(?P<ip>[\d\.]*)[^\[]*(?P<datum>[^\]]*)[^\"]*\"(?P<befehl>[^ ]*) (?P<pfad>[^ ]*) (?P<protokol>[^\"]*)[^\d]*(?P<zahlen>.*)$'
Gruppen mit Namen sind einfach übersichtlicher.

Re: Regex-Gruppen

Verfasst: Montag 15. Mai 2017, 07:20
von Taadu
Ich bin jetzt nach dem Beispiel von noisefloor vorgegangen und bekomme nun auch eine Ausgabe wie ich sie brauche bzw. haben möchte, jedoch habe ich jetzt das Problem, das ich am Ende eines Durchlaufs folgenden Fehler bekomme:
print((m.group()))
AttributeError: 'NoneType' object has no attribute 'group'

Ich verstehe jetzt nicht genau, wieso ich zwar die richtige Ausgabe bekomme wenn ich die jeweilige Gruppe ausgebe, aber ich trotzdem diese Meldung bekomme.

Re: Regex-Gruppen

Verfasst: Montag 15. Mai 2017, 08:49
von noisefloor
Hallo,

den Fehler kann ich so nicht nachvollziehen. Ich kann `m.group()` nicht nachvollziehen bzw. den Befehl beliebig oft aufrufen.

Was meinst mit
das ich am Ende eines Durchlaufs folgenden Fehler bekomme
? Bzw. welche Durchlauf meinst du? Benutzt du irgendwo einen Iterator?

Gruß, noisefloor

Re: Regex-Gruppen

Verfasst: Montag 15. Mai 2017, 10:36
von Taadu
noisefloor hat geschrieben: Bzw. welche Durchlauf meinst du? Benutzt du irgendwo einen Iterator?
Gruß, noisefloor

So sehr kenne ich mich mit der Materie nicht aus, ich kann zu Veranschaulichung aber eine runtergebrochene Version meines Quelltextes Zeigen.

Code: Alles auswählen

import re

antwort = open("antwort.txt", "a")



Pfad = "c:/Users/talib/Desktop/apache.log"
try:
    daten = open(Pfad)
except:
    print("Dateizugriff nichterfolgreich")
    exit(0)

for zeile in daten:
    regex = (r"^(.*?) (.*?) (.*?) \[(.*?)\] \"(.*?) (.*?) (.*?)\" (.*?) (.*?)$")
    p = re.compile(regex)
    m = p.match(zeile)
    print(m.group())

antwort.close()
In der Ausführung listet er mir, so wie ich das sehe alle Zeilen auf, aber zudem auch diese Meldung:
Traceback (most recent call last):
File "C:/Users/talib/PycharmProjects/untitled1/16 test.py", line 18, in <module>
print(m.group())
AttributeError: 'NoneType' object has no attribute 'group'

Re: Regex-Gruppen

Verfasst: Montag 15. Mai 2017, 10:42
von kbr
@Taadu: eine der Zeilen in der Datei passt vermutlich nicht auf die regex, daher wird kein Match-Objekt sondern None zurückgegeben.

Re: Regex-Gruppen

Verfasst: Montag 15. Mai 2017, 11:31
von noisefloor
Hallo,

teste doch mal vor dem `print`, ob `m ` überhaupt existiert:

Code: Alles auswählen

...
if m:
    print(m.group())
Zum Code: nackte `try ... except` sind schlecht, weil du _alle_ Fehler abfängst. Wenn du z.B. einen SyntaxError im Code hättest, dann würde bei dir auch "Datenzugriff nicht erfolgreich" stehen was mindestens mal irreführend ist. Wenn fängt man gezielt bestimmte Fehler ab.

Wenn bei dir eine Exception geworfen würde, würde die Datei nicht geschlossen, weil die Zeile mit `antworten.close()` nie erreicht würde. Das müsste wenn noch in einen `finally` Block.

Zum Öffnen von Dateien nimmt man normalerweise das `with` Statement, weil sich Python dann darum kümmert, dass die Datei auch wieder geschlossen wird.

Gruß, noisefloor

Re: Regex-Gruppen

Verfasst: Montag 15. Mai 2017, 11:47
von BlackJack
@Taadu: Noch eine Anmerkung zum Quelltext: Das `re.compile()` macht so keinen Sinn, denn wenn Du das gleiche Muster in jedem Schleifendurchlauf immer wieder in ein RegEx-Objekt übersetzt, könntest Du auch gleich `re.match()` verwenden.

Einbuchstabige Namen sind keine gute Idee. Ich rätsele immer noch was `p` eigentlich bedeuten soll.

`exit()` sollte man nur verwenden wenn es wirklich benötigt wird, was bei einer 0 als Argument eigentlich nie der Fall ist, denn das passiert auch ganz automatisch wenn das Programm am Ende angelangt ist. Und man kann Programme eigentlich immer so strukturieren, dass das Programmende mit dem ”natürlichen Ende” zusammenfällt. Ausnahme ist der Fall wo man explizit andere Werte als 0 als Rückgabecode an den aufrufenden Prozess übermitteln möchte. Ausserdem müsste man `exit()` aus dem `sys`-Modul importieren. Das es auch ohne geht ist ein undokumentiertes Implementierungsdetail von CPython.

Warum behandelst Du die Ausnahme *überhaupt*? Denn das Programm würde ja auch ohne die Behandlung bei einer Ausnahme abbrechen. Sogar mit mehr Informationen über das Problem was aufgetreten ist.

Re: Regex-Gruppen

Verfasst: Montag 15. Mai 2017, 12:11
von Taadu
Vielen Dank für die Rückmeldung alle Antworten waren mir wirklich sehr Hilfreich, auch der Hinweis das mein Regex nicht alles Abdecken könnte, hat sich bewahrheitet, das kam für mich eigentlich garnicht in Frage...

Re: Regex-Gruppen

Verfasst: Montag 15. Mai 2017, 12:35
von noisefloor
Hallo,
Einbuchstabige Namen sind keine gute Idee. Ich rätsele immer noch was `p` eigentlich bedeuten soll.
Das ist natürlich korrekt - im gegebenen Fall sind die Variablennamen an das offizielle Python-Howto zur Regex angelehnt: https://docs.python.org/3.5/howto/regex ... egex-howto

Kannst du dir jetzt aussuchen, ob das meine Post besser macht oder das Howto schlechter ;-)

Gruß, noisefloor

Re: Regex-Gruppen

Verfasst: Montag 15. Mai 2017, 13:13
von BlackJack
@noisefloor: Bei Deinem Code kann man ja noch sagen das ist kein Quelltext sondern eine Livesitzung in einer Python-Shell. Das ist ja alles kurz und übersichtlich und da hat so etwas wie leicht zu tippen gegenüber nach Jahren und mehreren Überarbeitungen noch verständlich zu lesen, auch einen anderen Stellenwert. :-)

Re: Regex-Gruppen

Verfasst: Dienstag 16. Mai 2017, 12:17
von beertonic
Ich würde dir empfehlern (.*?) zu vermeiden. Es ist zu unpräzise, weil es fast alles matcht.
Ich benutze sowas wie ([^#]*). Es matcht solange das Zeichen nicht # ist, aber da kann man natürlich alles einsetzen.

Re: Regex-Gruppen

Verfasst: Dienstag 16. Mai 2017, 12:51
von BlackJack
Ich würde beertonic da zustimmen. Insbesondere da wir ja jetzt auch wissen das dort durchaus Zeilen vorkommen die nicht dem Muster entsprechen, würde ich sicherstellen wollen das es nicht so leicht passieren kann, dass man Zeilen matcht die man gar nicht haben möchte weil das Suchmuster so/zu unscharf formuliert ist. Ausserdem würde ich „named groups“ mindestens für die Teilausdrücke verwenden, die für die Auswertung interessant sind. Das macht den Code verständlicher als irgendwelche magischen Indexzahlen.

Re: Regex-Gruppen

Verfasst: Dienstag 16. Mai 2017, 12:57
von beertonic
Ich habe weiter oben auch schon eine präzisere Version mit named groups gepostet.

Re: Regex-Gruppen

Verfasst: Dienstag 16. Mai 2017, 13:44
von Taadu
Danke für die Hilfreichen Tipps, jedoch habe eine Frage, die nicht mehr viel mit Regex zu tun hat, ich frage mich gerade, ob es möglich ist eine Variable wie eine Textdatei zu beschreiben also vom Aufbau her. Ich habe nämlich das problem, das ich eine bestimmte Zeilenstruktur nur am Ende bzw. Anfang ausgeben will, also muss ich sie vorher irgendiwe zwischenspeichern (möglicherweise in einer Liste?), erst wollte ich mit Hilfe eines Zählers automatisch immer neue Variablen erstellen lassen, um diese dann am Ende in die Textdatei schreiben zu lassen, dann habe ich hier im Forum aber gelesen das dies vermieden werden sollte, vielleicht hat auch hier jemand einen Vorschlag für mich.

Mit einem solchen versuch

Code: Alles auswählen

        ausgabe = (zeile +zeile)
hat er "ausgabe" nur immer mit der neusten "Wert" überschrieben

Re: Regex-Gruppen

Verfasst: Dienstag 16. Mai 2017, 14:22
von beertonic
Nimm eine Liste

Code: Alles auswählen

liste.append(zeile+zeile)
Wenn du Variablen bis zum nächsten Programmaufruf speichern willst kannst du das mit pickle machen, oder einfach in eine Datei schreiben.
http://www.python-kurs.eu/dateien.php

Re: Regex-Gruppen

Verfasst: Dienstag 16. Mai 2017, 14:26
von BlackJack
@Taadu: Sammel die Daten doch einfach in einer Liste. Oder schreibe sie vor bzw. nach den anderen Zeilen in die Textdatei.