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

Code: Alles auswählen

'^(\s*)((\S+)(\s*))+$'
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:

Code: Alles auswählen

map(len, re.findall(r"\S+|\s+", text))

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:

Code: Alles auswählen

map(len, re.findall(r"\S+|\s+", text))
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