Seite 1 von 1

regex: bestimmte zeilen suchen

Verfasst: Samstag 3. Juli 2010, 10:15
von Francesco
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.

Re: regex: bestimmte zeilen suchen

Verfasst: Samstag 3. Juli 2010, 10:55
von cofi
Im Zweiten Fall findet er eben den Teilstring _bis_ zu '#'.

Code: Alles auswählen

re.search('^ +[^#].*', astring)

Re: regex: bestimmte zeilen suchen

Verfasst: Samstag 3. Juli 2010, 10:59
von DaMutz

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 *.

Re: regex: bestimmte zeilen suchen

Verfasst: Samstag 3. Juli 2010, 11:00
von Francesco
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.

Re: regex: bestimmte zeilen suchen

Verfasst: Samstag 3. Juli 2010, 11:03
von Francesco
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.

Re: regex: bestimmte zeilen suchen

Verfasst: Samstag 3. Juli 2010, 11:06
von cofi
Aber ehrlich gesagt, finde ich folgendes besser geeignet:

Code: Alles auswählen

code = (line for line in fobj if not line.lstrip().startswith("#"))

Re: regex: bestimmte zeilen suchen

Verfasst: Samstag 3. Juli 2010, 11:08
von sma

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

Re: regex: bestimmte zeilen suchen

Verfasst: Samstag 3. Juli 2010, 12:54
von Francesco
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?

Re: regex: bestimmte zeilen suchen

Verfasst: Samstag 3. Juli 2010, 13:43
von BlackJack
@Francesco: Wegen dem `re.M`. Damit können Treffer auch über mehrere Zeilen gehen.

Re: regex: bestimmte zeilen suchen

Verfasst: Samstag 3. Juli 2010, 13:58
von sma
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

Re: regex: bestimmte zeilen suchen

Verfasst: Samstag 3. Juli 2010, 14:43
von Francesco
@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.

Re: regex: bestimmte zeilen suchen

Verfasst: Samstag 3. Juli 2010, 22:52
von sma
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

Re: regex: bestimmte zeilen suchen

Verfasst: Samstag 3. Juli 2010, 23:09
von Francesco
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.