regex: bestimmte zeilen suchen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

hallo, ich möchte Zeilen suchen, deren erstes zeichen nach ein oder mehreren spaces nicht '#' ist.

Wenn ich angebe:

Code: Alles auswählen

re.search('^ +[^#]', meinstring)
findet sowohl meinstring:

Code: Alles auswählen

'    print "test"'
als auch

Code: Alles auswählen

'    #print "test"'
(dessen zeile aber mit ein oder mehr spaces und '#' beginnt)

Was ist hier falsch? :roll:

Nachtrag: hm, brauche ich da eine lookbehind assertion? Die Frage ist aber hauptsächlich, warum er die Zeile mit dem beginnenden Kommentar trotzdem findet.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Im Zweiten Fall findet er eben den Teilstring _bis_ zu '#'.

Code: Alles auswählen

re.search('^ +[^#].*', astring)
Benutzeravatar
DaMutz
User
Beiträge: 202
Registriert: Freitag 31. Oktober 2008, 17:25

Code: Alles auswählen

re.search('^\s*[^#]*$', meinstring)
Ich würde den Leerschlag durch \s ersetzen, es könnte auch sein, dass die Zeile vor dem # kein Leerzeichen hat, darum der *.
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

cofi hat geschrieben:Im Zweiten Fall findet er eben den Teilstring _bis_ zu '#'.

Code: Alles auswählen

re.search('^ +[^#].*', astring)
Danke, da behandelt er das letzte space als [^#] und geht nicht bis zum letzen space. Das habe ich hier falsch aufgefasst.
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

DaMutz hat geschrieben:

Code: Alles auswählen

re.search('^\s*[^#]*$', meinstring)
Ich würde den Leerschlag durch \s ersetzen, es könnte auch sein, dass die Zeile vor dem # kein Leerzeichen hat, darum der *.
Ja das ist sicher besser. könnte ja sein, dass die zeile mit tabs beginnt.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Aber ehrlich gesagt, finde ich folgendes besser geeignet:

Code: Alles auswählen

code = (line for line in fobj if not line.lstrip().startswith("#"))
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Code: Alles auswählen

import re
s = """
  print 1
  #print 2
  print 3
"""
print(re.findall(r"^ +[^ #].*$", s, re.M))
Das `[^#]` alleine funktioniert nicht, denn dann findet der reguläre Ausdruck eben das Leerzeichen davor (wenn's mindestens 2 sind).

Stefan
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

Jetzt habe ich noch ein kleines Problem:
wenn ich das so angebe (es soll 0 oder mehr spaces am anfang suchen):

Code: Alles auswählen

import re
s = """
print 1
#print 2
print 3
"""
print(re.findall(r"^ *[^ #].*$", s, re.M))
bekomme ich:

Code: Alles auswählen

['\nprint 1', 'print 3']
warum ist das \n plötzlich da?
BlackJack

@Francesco: Wegen dem `re.M`. Damit können Treffer auch über mehrere Zeilen gehen.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Das \n ist die allererste Leerzeile. Es trifft leider auf [^# ] zu.

Dies sollte gehen wenn man sie auch haben will:

Code: Alles auswählen

re.findall(r"^$|^ *[^ #].*$", s, re.M)
alternativ um sie gleich wegzufiltern:

Code: Alles auswählen

re.findall(r"^ *[^ #\n].*$", s, re.M)
oder

Code: Alles auswählen

re.findall(r"^ *[^#\s].*$", s, re.M)
Das "umdrehen" von Bedingungen in regulären Ausdrücken ist trickreich. Daher ist vielleicht dies die einfachste Lösung:

Code: Alles auswählen

for l in s.splitlines():
    if not re.search(r"^ *#", l):
        print(l)
Statt `print` könnte man ein `yield` nehmen und das ganze in eine Funktion packen und man hat einen schicken Iterator.

Stefan
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

@Blackjack: Ja, aber warum das erste Zeichen '\n' als das erste Zeichen nach Zeilenanfang ( '^') mitgenommen wird, verstehe ich trotzdem nicht. gilt das multiline sowohl als stringbeginn als auch für Zeilenbeginn (so schätze ich wird es wohl sein)

@Stefan. Das mit der umgekehrten Abfrage finde ich auch eine sehr gute Idee.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Francesco hat geschrieben:@Blackjack: Ja, aber warum das erste Zeichen '\n' als das erste Zeichen nach Zeilenanfang ( '^') mitgenommen wird, verstehe ich trotzdem nicht.
Ich hatte die Erklärung eigentlich gegeben. Schau dir den Anfang des Strings an: \nprint1\n#print2...

Das `findall` beginnt bei Index 0. Dies ist ein Zeilenanfang, also passt ^. Nun sollen 0 oder mehr Leerzeichen folgen. Das passt, denn es folgen 0 Leerzeichen. Nun soll ein zeichen folgen, das kein Leerzeichen oder # ist. Das \n (denn ich bin immer noch an Index 0) ist so ein Zeichen, also wird das genommen. Nun werden mit .* (da re.S == DOTALL nicht gesetzt ist) alles bis zum nächsten Zeilenende bzw. Ende des Strings gelesen, in diesem Fall print1. Das folgende \n wird ebenfalls verschluckt und `findall` würde jetzt bei #print weitersuchen.

Stefan
Francesco
User
Beiträge: 824
Registriert: Mittwoch 1. Dezember 2004, 12:35
Wohnort: Upper Austria

sma hat geschrieben: Ich hatte die Erklärung eigentlich gegeben. Schau dir den Anfang des Strings an: \nprint1\n#print2...

Das `findall` beginnt bei Index 0. Dies ist ein Zeilenanfang, also passt ^. Nun sollen 0 oder mehr Leerzeichen folgen. Das passt, denn es folgen 0 Leerzeichen. Nun soll ein zeichen folgen, das kein Leerzeichen oder # ist. Das \n (denn ich bin immer noch an Index 0) ist so ein Zeichen, also wird das genommen. Nun werden mit .* (da re.S == DOTALL nicht gesetzt ist) alles bis zum nächsten Zeilenende bzw. Ende des Strings gelesen, in diesem Fall print1. Das folgende \n wird ebenfalls verschluckt und `findall` würde jetzt bei #print weitersuchen.

Stefan
Ja danke, jetzt ist es mir klar.
Antworten