Seite 1 von 1

Reguläre Ausdrücke: Validieren & splitten in einem Rutsch?

Verfasst: Samstag 19. März 2011, 20:22
von doppelkeks
Nichts wichtiges, nur aus Interesse...
ich hab es nicht hinbekommen, in einem Rutsch einen String sowohl zu validieren als auch in Häppchen zu zerhacken.

Wenn ich re.match nutze, dann finde ich in .groups() immer nur ein einziges Element (das zuletzt gefundene).
Wenn ich zB mit re.findAll rüberlaufe, dann merke ich nicht, wenn etwas verbotenes im string drin war.
Einfach nur aus Prinzip fuchst es mich, zweimal den ausdruck parsen zu müssen :)

Konkretes Beispiel:
Die Worte der zu validierenden Sprache bestehen aus einem 'n' oder 'd' gefolgt von einer Zahl. Es können beliebig viele Worte aneinander gereiht werden (zB: n1d2n5d9d7). Als Regex: '^([dn]\d)+$'
Jetzt möchte ich einerseits sicherstellen, dass ein Ausdruck nirgendwo die Grammatik verletzt, anderseits möchte ich die char-int Paare extrahieren.
Derzeit mach ich das in zwei Durchgängen:

Code: Alles auswählen

if not re.match(r'^([nd]\d)+$', expr):
    raise SomeError
for x in re.findall(r'[nd]\d', expr):
    print x
Ich schätze, ich steh einfach auf dem Schlauch, aber bin zu dickköpfig um es einfach gut sein zu lassen :roll:

Re: Reguläre Ausdrücke: Validieren & splitten in einem Rutsc

Verfasst: Samstag 19. März 2011, 20:34
von deets
Ich denke nicht, dass das geht. Die Doku ist da eindeutig:

"""
Returns one or more subgroups of the match. If there is a single argument, the result is a single string;
"""

http://docs.python.org/library/re.html# ... ject.group

Es ist also immer nur der letzte Wert, der eine Gruppe gematcht hat. Damit bist du leider festgenagelt auf deine Loesung.

Re: Reguläre Ausdrücke: Validieren & splitten in einem Rutsc

Verfasst: Samstag 19. März 2011, 21:04
von DaMutz
du verwendest aber auch 2 Unterschiedliche reguläre Ausdrücke... Wenn du zweimal den selben Ausdruck hättest könntest du es so machen:

Code: Alles auswählen

import re

expr = 'n1d2n5d9d7'

pattern = re.compile(r'[nd]\d')

if not pattern.match(expr):
    raise SomeError
for x in pattern.findall(expr):
    print x
und falls der reguläre Ausdruck wirklich so einfach ist (und die Zahl immer aus einer Ziffer besteht), so könntest du im ersten Schritt validieren (wie bisher) und für das splitten bräuchtest du ja keinen regulären Ausdruck mehr, sondern könntest einfach mit jedem Schleifendurchgang 2 Zeichen verarbeiten.

Re: Reguläre Ausdrücke: Validieren & splitten in einem Rutsc

Verfasst: Samstag 19. März 2011, 21:15
von deets
Das wuerde ihm aber auch nicht wirklich was bringen. Denn das was hier teuer ist (fuer welche Definition von "teuer" auch immer) ist ja genau die mehrfache iteration. Wenn die rexe das direkt aufsammeln wuerden, koennte man sich das sparen. Ob sich das Laufzeitverhalten nu aber gross aendert, durch dich impliziten appends, statt expliziter Verarbeitung - who knows. Der OP hat ja schon selbst gesagt, dass es eher ein "ich *will* aber!!!"-ding ist ;)

Re: Reguläre Ausdrücke: Validieren & splitten in einem Rutsc

Verfasst: Samstag 19. März 2011, 22:06
von BlackJack
Wozu braucht man denn da unbedingt `re`?

Code: Alles auswählen

source = 'n1d2n5d9d7'
result = list()
for character, digit in (source[i:i+2] for i in xrange(0, len(source), 2)):
    if not (character in 'nd' and digit.isdigit()):
        raise Exception
    print character + digit

Re: Reguläre Ausdrücke: Validieren & splitten in einem Rutsc

Verfasst: Samstag 19. März 2011, 22:36
von deets
@BlackJack

Weil's eine von wahrscheinlich 5 regulaeren Ausdrucks-basierten Loesungen ist, die tatsaechlich besser aussieht als deine :P

Re: Reguläre Ausdrücke: Validieren & splitten in einem Rutsc

Verfasst: Sonntag 20. März 2011, 01:11
von doppelkeks
Stimmt, ich "wollte es einfach so", und war angerissen, weil ichs nicht hinbekam

Hatte mich für re entschieden, weil
  • ich dachte, dass mein Parser mindestens fünfmal so lang geworden wäre wie BlackJacks... (elegant deine Lösung, gefällt mir)
  • ich vermutete, dass eine re Lösung in jedem Falle effizienter als eine python-Schleife sein wird.
Eigentlich ist die Geschwindigkeit hier aber wirklich egal, die Ausdrücke sind kurz, selbst 0.1 mal so schnell wäre sicherlich nicht spürbar. Mir gings einfach ums Prinzip, Eleganz, Spass und um Vermehrung von Wissen über das re Modul.

Ich hab einfach mal aus Interesse versucht, Deine Schleife so umzunudeln, dass eine "offene" for Schleife vermieden wird, aber mein Ergebnis ist nicht besser. Ich brauch zwei vollständige Durchläufe über den String und außerdem mehr Speicher :|
Aber weil ich jetzt ne Weile dran saß, (eigentlich wollt ich schon vor längst im Samstagabend_Partymodus sein...) poste ich es trotzdem :P

Code: Alles auswählen

s = 'n1d3n2n5'
result = [(c, int(d)) for c,d in zip(s[0::2], s[1::2]) if c in 'nd' and d.isdigit()]
if len(result)*2 != len(s):
    raise Exception