Seite 1 von 1
Wieder mal Regular Expressions
Verfasst: Mittwoch 21. Februar 2007, 13:25
von HWK
Hallo!
Ich möchte eine Zeile folgender Form
Code: Alles auswählen
(x1 * '\s') + (x2 * '\S') + (x3 * '\s' + x4 * '\S') + (x5 * '\s' + x6 * '\S') + ... + xn * '\s'
\s = Whitespace, \S = Non-Whitespace, x? in [0, 1, 2, ...], aber x2 in [1, 2, 3, ...]
in die abwechselnden Whitespace- und Non-Whitespace-Gruppen aufteilen, wobei mich eigentlich nur deren Längen interessieren.
Es sollen also z.B. folgende Zeilen zerlegt werden können:
Code: Alles auswählen
10 * ' ' + 10 * '+' + 10 * ' ' + 10 * '-' + 10 * ' '
und
10 * '+'
Ich habe gehofft, es mit REs lösen zu können. Meine Versuche sind aber bisher kläglich gescheitert, z.B.:
Hat jemand eine Idee oder muss ich es doch über eine selbst geschreibene Funktion lösen?
Danke
HWK
Verfasst: Mittwoch 21. Februar 2007, 13:39
von birkenfeld
Benutze finditer():
Code: Alles auswählen
rex = re.compile(r"(\s*)(\S*)")
for match in rex.finditer(text):
len_space = len(match.group(1))
len_notspace = len(match.group(2))
...
Mit "\S*" kannst du Leerzeichen am Ende mit derselben RE abdecken,
bekommst aber am Schluss immer einen leeren Match.
Verfasst: Mittwoch 21. Februar 2007, 13:41
von rayo
Dein Ausdruck funktioniert ja.
Nur dein Problem wird nicht der reguläre Ausdruck selbst sein sondern das Resultat. Wiederholte Gruppen, bei dir ((\S+)(\s*))+, geben im Resultat nur eine Matchgroup zurück, der Rest wurde bei jeder Wiederholung überschrieben.
Als Resultat bekommst du:
1. Gruppe: der erste Block Leerzeichen
2. Gruppe: letzer Match der Gruppe non-whitespaces;whitespaces
3. Gruppe: non-whitespaces der 2. Gruppe
4. Gruppe: die letzten whitespaces der Gruppe 2
Gruss
*edit* ja da war birkenfeld mal wieder ein wenig schneller

nimm keinen Ausdruck für alles sondern nur den Wiederholten teil
Verfasst: Mittwoch 21. Februar 2007, 21:06
von HWK
Prima! Vielen Dank.
Ich hatte es zwar zwischenzeitlich schon ohne REs gelöst, aber ich habe wieder etwas dazu gelernt. Hier einmal beide Varianten:
Code: Alles auswählen
def my_split(self, text):
flag = text[0].isspace()
cnt = 0
result = []
for c in text:
if c.isspace() == flag:
cnt += 1
else:
result.append(cnt)
flag = not flag
cnt = 1
result.append(cnt)
return result
def my_split(self, text):
result = []
rex = re.compile('(\s*)(\S*)')
for match in rex.finditer(text):
result.append(len(match.group(1)))
result.append(len(match.group(2)))
for i in (0, -3):
if result[i] == 0:
del(result[i])
return result[:-2]
MfG
HWK
Verfasst: Freitag 23. Februar 2007, 02:15
von PmanX
Hallo,
ich denke, die RegEx funktioniert nicht.
Code: Alles auswählen
#
>>> rc = re.compile(r"""
(\s*) # 0 or more repetitions
(\S*) # 0 or more repetitions
""", re.VERBOSE)
Diese RegEx muß auf gar nichts passen!
Wenn Whitespaces
keine Trenner sind, greift sich \S* gleich
den nächsten Token.
Gruß P.
Verfasst: Freitag 23. Februar 2007, 13:20
von birkenfeld
Hast du deine Gedanken auch ausprobiert?
Verfasst: Freitag 23. Februar 2007, 13:27
von HWK
PmanX hat geschrieben:Hallo,
ich denke, die RegEx funktioniert nicht.
Doch! Sie tut genau das, was ich brauche. Sie liefert mir die Längen der Blöcke mit Whitespaces bzw. Non-Whitespaces zurück. Die Ergebnisse sind identisch zu meiner Alternative. Es mag sein, dass Sie bei anderen Ausgangsstrings nicht funktionieren würde, die bearbeiteten Strings erfüllen aber feste Kriterien. Sie bestehen nur abwechselnd aus Blöcken von Leerzeichen und anderen ASCII-Zeichen. Ich hätte also statt '\s*' auch ' *' nehmen können.
MfG
HWK
Verfasst: Freitag 23. Februar 2007, 14:25
von PmanX
birkenfeld hat geschrieben:Hast du deine Gedanken auch ausprobiert?
Es ist die RegEx, halt nur
re.X. Oder anders, welche Gedanken habe ich unterlassen?
HWK:
Beim Gebrauch von regulären Ausdrücken und bei deren Anwendung auf Daten in bestimmten Situationen werden meist stillschweigend Annahmen getroffen, und es ist oft notwendig, sich diese bewußt zu machen.
Um die RegEx zu beschreiben, fehlen einige Informationen.
Konkret: Soll zeilenorientiert gearbeitet werden und soll der erste Token von Whitespaces wahlfrei sein?
Da würde ich zweistufig arbeiten.
1) Whitespaces am Zeilenanfang entfernen.
2) Über Zeile iterieren und die Token auswerten.
Re: Wieder mal Regular Expressions
Verfasst: Freitag 23. Februar 2007, 16:00
von Luzandro
Wenn ich dich richtig verstanden habe, müsste auch das reichen:
Verfasst: Freitag 23. Februar 2007, 16:46
von PmanX
Code: Alles auswählen
(x1 * '\s' + x2 * '\S') # (\s*\S+)
(x3 * '\s' + x4 * '\S') # (\S*\s*)
(x3 * '\s' + x4 * '\S')
x? in [0, 1, 2, ...] # .*
x2 in [1, 2, 3, ...] # \S+
Hier braucht nur ein Token mit
NonWhitespaces vorkommen.
Was ich nicht verstehe, wenn ein Token aus (Whitespaces &
NonWhitespaces) bestehen soll, *EDIT* dann sollte x1 \s+ sein.
Wenn ich die Anforderung richtig erfasst habe, ist diese Lösung ausreichend und gefällt

Re: Wieder mal Regular Expressions
Verfasst: Freitag 23. Februar 2007, 22:45
von HWK
Luzandro hat geschrieben:Wenn ich dich richtig verstanden habe, müsste auch das reichen:
Tatsächlich. Das ist echt toll.
PmanX hat geschrieben:Was ich nicht verstehe, wenn eine Token aus (Whitespaces & NonWhitespaces) bestehen soll, *EDIT* dann sollte x1 \s+ sein.
Nein. Whitespaces am Anfang sind nicht zwingend. Es handelt sich auch nicht um Tokens.
PmanX hat geschrieben:Wenn ich die Anforderung richtig erfasst habe, ist diese Lösung ausreichend und gefällt.
Welche Lösung?
Verfasst: Samstag 24. Februar 2007, 00:21
von PmanX
Wie wäre es mit
Code: Alles auswählen
map(len, re.findall(r'\S+|\s+', re.sub(r'^\s+', '', line)))
?
Verfasst: Samstag 24. Februar 2007, 00:47
von birkenfeld
re.sub(r'^\s+', '', line) ist schneller und einfacher line.lstrip(),
ansonsten ist das doch ne schöne Lösung.
Verfasst: Samstag 24. Februar 2007, 13:48
von HWK
Ich brauche aber auch die Länge des evtl. am Anfang stehenden Whitespace-Blocks. Deshalb ist Luzandros Lösung die für mich passende und auch noch kürzer.
Allen herzlichen Dank
HWK