Laden...

RegEx --> String mit fester Spaltenbreite prüfen

Erstellt von HiJack82 vor 6 Jahren Letzter Beitrag vor 6 Jahren 4.126 Views
H
HiJack82 Themenstarter:in
19 Beiträge seit 2014
vor 6 Jahren
RegEx --> String mit fester Spaltenbreite prüfen

Hallo zusammen. Ich versuche gerade schon eine Weile mit Hilfe von Google folgendes zu realisieren:

Ich habe folgenden String:
"HALLO .W"

Folgendes ist zu prüfen:

  • Die Größe des Strings müssen genau 9 Zeichen sein
  • Die Letzten beiden Zeichen müssen immer .W sein
  • Das Erste Zeichen muss [A-Za-z0-9] sein
  • Dazwischen dürfen 6 mal [A-Za-z0-9] oder Leerzeichen sein
    --> wobei nur am Ende (also vor dem Punkt) Leerzeichen erlaubt sind
    --> und nicht zwingend ein Leerzeichen dabei sein muss

Beispiel für erlaubt:


"HALLO  .W"
"H      .W"
"HALLO12.W"

Beispiel für verboten:


"  HALLO.W"
"H.W"

Das kann doch eigentlich nicht so schwer sein, aber ich komme leider nicht drauf.
Ich weiß z.B. nicht wie ich definieren kann, dass ich beliebig viele Leerzeichen haben darf, aber diese nur am Ende stehen dürefen.

Hat vielleicht jemand von den RegEx Cracks einen Tipp für mich?

2.078 Beiträge seit 2012
vor 6 Jahren

Beliebig viele Leerzeichen: \s*
Oder einfach ein Leerschritt anstelle von \s
Regex erlaubt das, würde ich aber unter Umständen von absehen, da man diese Toleranz auch aus stellen kann.

Dass diese Leerzeichen nur vor dem ".W" am Ende erlaubt sind:
Du baust den Teil des Patterns vorher so wie gewollt und schreibst am Ende das "\s*.W" ein und fertig

Vergiss nicht "^" am Anfang und "$" am Ende zu schreiben, das stellt sicher, dass der gematchde String auch der ganze String ist. Voraus gesetzt, Du willst das überhaupt

Ein Tipp noch: https://regex101.com/
Ist sehr hilfreich, wenn Du mit Regex arbeitest
Da kannst Du auch mit STRG+S speichern und bekommst dann einen Link, der immer mit dem Pattern und dem Text ausgestattet ist, was zu dem Zeitpunkt drin stand.

PS:
Auf die Länge würde ich per Code (myString.Length == 9) prüfen, ist mit Abstand das Einfachste.
In Regex geht das bestimmt auch, aber ist das wirklich notwendig?

PPS:
In regex101, wenn Du da mehrere Zeilen im Text auf einmal prüfen willst, musst Du vorher in den Regex-Flags (rechts vom Pattern) auf MultiLine stellen. Ansonsten prüft er immer den kompletten Text (mit Zeilenumbrüchen), das passt dann natürlich nicht

PPPS:
Schau dir mal "\w" an, das entspricht "[a-zA-Z0-9_]", beachte den Unterstrich, der am Ende mit drin steht.
Wenn das in Frage kommt, würde ich eher zu dem raten, weil das die doch recht unübersichtlichen Regex-Patterns mMn. etwas übersichtlicher gestaltet.

49.485 Beiträge seit 2005
vor 6 Jahren

Hallo Palladin007,

In Regex geht das bestimmt auch ...

klar geht das, z.B. mit einem look ahead gleich am Anfang:

^(?=.{9}$)

... aber ist das wirklich notwendig?

Das kann in bestimmten Fällen durchaus nötig sein, insbesondere immer dann, wenn Pattern erst zur Laufzeit von Außen kommt (z.B. per Benutzereingabe oder aus einer Datei).

Hallo HiJack82,

was genau ist denn dein Problem? Du hat ja sehr genau beschrieben, was du machen willst. Das kannst du im Grunde 1:1 in Regex umsetzen, nötigenfalls mit Hilfe von [Artikel] Regex-Tutorial. Die einzige Klippe ist das mit der Länge, für die jetzt zwei Lösungen bekommen hast.

Ein Tipp noch:
>

oder offline: On-the-fly Regex-Tester: Regex-Lab

herbivore

2.078 Beiträge seit 2012
vor 6 Jahren

Hallo herbivore,

dass das geht, weiß ich, aber wenn's nicht zwingend notwendig ist, würde ich das nicht tun.
Gerade wenn Regex nur eine lokale Hilfe im Code sein soll, dann würde ich eher per Length prüfen.
Außerdem kommt hier gleich eine weitere "Komplexitäts-Stufe" (Wegen Lookahead) dazu kommt, die viele (Anfänger) noch nicht kennen/verstehen.

Vermutlich ist es auch besser, einfache Patterns nicht mit Regex zu prüfen.
Das kann schneller sein, hauptsächlich verbessert es aber die Wartbarkeit, besonders, wenn im Laufe der Zeit jemand daran arbeiten muss, der Regex nicht fließend spricht.
Darf ich mir auf der Arbeit auch manchmal anhören, weil ich das Eine oder Andere mal relativ komplexe Regex-Patterns eingebaut habe 😄

Wenn das nicht anders geht (z.B. wenn es aus der Config kommt), dann sieht das natürlich anders aus.
Was nun der beste Weg ist, kann wohl nur HiJack82 zuverlässig entscheiden.

In dem Sinne der Wink zu HiJack82:
Ist Regex überhaupt notwendig?
Das Pattern lässt sich auch sehr einfach direkt in Code prüfen.

Ich kenne es z.B. bei mir, dass ich mir manchmal auf die Finger hauen muss, dass ich Regex an der Stelle eigentlich gar nicht brauche 😄

49.485 Beiträge seit 2005
vor 6 Jahren

Hallo Palladin007,

Das kann schneller sein, hauptsächlich verbessert es aber die Wartbarkeit

meine Erfahrung ist genau andersherum. Bei mir war Regex nicht nur deutlich leichter und schneller zu erstellen, sondern auch flexibler und immer deutlich leichter wartbar, gerade wenn die Aufgabe komplexer ist. Auch bei meiner Aufgabe im Programmierspiel kam dN!3L in seiner abschließenden Lösung zu einem ähnlichen Fazit:

Wenn ich den Aufwand der ganzen Nacharbeiten noch mit dazurechne, sind reguläre Ausdrücke eindeutig einfacher erstellt und man findet Fehler schneller.

Ich persönlich habe noch an keiner einzigen Stelle bereut, Regex eingesetzt zu haben, egal wie einfach oder komplex die Aufgabe war, ganz im Gegenteil.

Man darf auch nicht vergessen, dass ein Pattern nur dann komplex wird, wenn die Komplexität schon in der Aufgabe steckt und dann ergibt auch das Ausprogrammieren komplexen - und meiner Erfahrung nach eben sogar noch komplexeren - Code.

Aber auch hier gilt: Wir haben unsere Meinungen und Erfahrungen geteilt. Entscheiden muss HiJack82.

herbivore

PS: Wenn man die Lesbarkeit von Pattern für komplexere Aufgaben erhöhen möchte, gibt es zwei gute Möglichkeiten. Zum einem kann man Pattern per RegexOptions.IgnorePatternWhitespace nicht nur mit Leerzeichen und Zeilenumbrüchen strukturieren und damit deutlich lesbarer machen, sondern mit # sogar beliebige Kommentare einfügen. Zum anderen kann man die einzelnen Teilpattern ganz simpel in einzelne, sprechend benannten Variablen speichern und daraus erst am Schluss den Gesamtpattern (z.B. mit String) zusammenbauen. Auch hier entsteht der die Lesbarkeit fördernde Effekt vor allem durch die Kombination von Strukturierung und Kommentierung.

H
HiJack82 Themenstarter:in
19 Beiträge seit 2014
vor 6 Jahren
Funktioniert leider noch nicht

Hallo zusammen,

erstmal vielen lieben Dank für all die Mühe. Es ist aber leider noch nichts passendes dabei.

\s* kann ich ja nicht verwenden, weil ich nicht beliebig viele Leerzeichen zulassen kann.
Ich versuche nochmal mein Kernproblem besser zu beschreiben.

  • Der gesamte String darf aus 9 Zeichen bestehen.
  • Die letzten beiden müssen immer .W sein
  • Das erste muss \w sein (danke Palladin00)

--> Jetzt kommt das eigentliche Problem:
Jetzt sind noch 6 Zeichen in der Mitte übrig.
\s* darf ich nicht machen weil nicht beliebig viele Leerzeichen vorkommen dürfen
\s{n} kann ich auch nicht machen, weil ich n nicht kenne.

Das Problem ist also, dass ich 6 Zeichen habe die mit \w anfangen und eventuell (muss nicht sein) mit \s enden.** Ich weiß nicht wie viele Zeichen und wie viele Leerzeichen da kommen. Ich weiß nur, dass es an der Stelle insgesamt 6 sind und Leerzeichen nur am Ende erlaubt sind. **Sorry, aber das ist echt schwierig zu erklären.

@Palladin007: Eigentlich ist RexEx nicht notwendig. Aber ich bewundere das Problem 😃 und bin extrem neugierig ob das mit RegEx überhaupt lösbar ist.

@Herbivore: Mein Problem ist, dass ich die ganzen Tutorials bereits gelesen habe, mein Problem damit aber nicht lösen kann.

49.485 Beiträge seit 2005
vor 6 Jahren

Hallo HiJack82,

die Lösung mit dem Problem der festen Länge habe ich oben bereits geschrieben. Wenn du den look ahead Pattern an den Anfang deines Pattern schreibst, dann ist sichergestellt, dass der String insgesamt genau 9 Zeichen hat und dadurch kannst du an der fraglichen Stelle einfach + bzw. * verwenden.

herbivore

H
HiJack82 Themenstarter:in
19 Beiträge seit 2014
vor 6 Jahren

Hallo noch mal,

wie im letzten Beitrag erwähnt. Die Länge ist nicht das Problem.

Vielleicht kannst Du mit einfach mal das Pattern hinschreiben, dann kann ich es mit https://regex101.com/ prüfen und hoffentlich auch verstehen.

Ich habe jetzt folgendes:

(^(?=.{9}$))(\w)**(\w|\s){0,6}**(\.W)

Ich glaube im Fett gedruckten Teil liegt noch mein Problem.

Das deckt aber immer noch nicht die Einschränkung ab, dass Leerzeichen nur am Ende (also vor dem .W) zulässig sind.

Das würde also fälschlicherweise auch als richtig bezeichnet.

HAL LO.W

Hinweis von Abt vor 6 Jahren

Habe das Code-Tag in ein TT-Tag umgewandelt, sodass Dein fett funktioniert.

2.078 Beiträge seit 2012
vor 6 Jahren

Du brauchst nicht zwangsläufig Gruppen nutzen, die erhöhen nur die Anzahl Klammern, in deinem konkreten Fall hast Du aber keinen Vorteil dadurch.
Der einzige Fall, wo es wirklich notwendig ist, ist die Kombination von \w ODER \s
Das aber nur als Tipp, an der Funktion sollte das nicht viel ändern

Du machst immer noch den Fehler, dass Du nicht die Länge von 0 bis 6 prüfen solltest. Du sagst doch selber, dass Du diese Länge gar nicht weist.
Was Du tust: Du verlangst einmal \w und danach entweder \w oder \s in beliebiger Reihenfolge und maximal 6 mal.
Gebe vor, dass vorne mindestens einmal \w (danach beliebig oft, schau dir das + an) und danach beliebig oft \s stehen darf - gefolgt durch die zwei Schluss-Zeichen. Dieses Pattern würde deine Regeln befolgen, außer die feste Länge.

Erst dann kümmerst Du dich um die Gesamtlänge von 9 Zeichen, indem Du das mit einem Lookahead prüfst.

PS:
Im Code-Tag kannst Du nicht fett markieren 😛
Ich würde den Code-Tag weg lassen, Regex wird sowieso nicht formatiert und bekommt auch kein Highlighting

49.485 Beiträge seit 2005
vor 6 Jahren

Hallo HiJack82,

(\w)(\w|\s){0,6}

wenn du willst, dass erst \w+ kommt und dann \s* folgt, dann schreib genau das. Um die (Gesamt-)Länge kümmert sich wie gesagt der look ahead.

herbivore

H
HiJack82 Themenstarter:in
19 Beiträge seit 2014
vor 6 Jahren

Vielen Dank Paladin007. Deine Tipps sind wirklich sehr hilfreich!
Die Klammern habe ich noch drin, weil man so im https://regex101.com/ schön die resultate der einzelnen Gruppen sieht. Das hätte ich dann später auch wieder entfernt.

Was Du tust: Du verlangst einmal \w und danach entweder \w oder \s in beliebiger Reihenfolge und maximal 6 mal.

Jetzt kommen wir der Sache schon näher. Das kann ich so nicht benutzen. Wenn ich nach \w 6 mal \w oder \s zulasse würde ABC DEF.W auch akzeptiert werden. Das darf ich aber nicht akzeptieren.

H
HiJack82 Themenstarter:in
19 Beiträge seit 2014
vor 6 Jahren

@herbivore:
Das war auch mein erster Gedanke. Das ist leider falsch.
Diese Abfrage würde "ABC DEF.W" erlauben. Leerzeichen dürfen aber nur am Ende und vor dem .T vorkommen (müssen aber nicht).

D
985 Beiträge seit 2014
vor 6 Jahren

Kurz und schmerzlos:

^(?=.{9}$)\w+\s*\.W$

49.485 Beiträge seit 2005
vor 6 Jahren

Hallo HiJack82,

Diese Abfrage würde "ABC DEF.W" erlauben.

nein, das würde das von mir vorgeschlagene \w+\s* eben nicht!

herbivore

2.078 Beiträge seit 2012
vor 6 Jahren

\w+\s*\.W erlaubt:
Mindestens ein \w, kein Leerzeichen
Danach beliebig oft \s
Zum Schluss die Zeichenkette ".W"

Das ist genau das, was Du haben willst, genau das hast Du im Eingang geschrieben.
Es wurde ja schon mehrfach geschrieben: Ignoriere die Länge, das tut der Lookahead

Hier ein regex101-Link: https://regex101.com/r/DwYZ6F/1
Da ist (fast) das Pattern, was Sir Rufo auch gepostet hat, einzig das $ fehlt im Lookahead.

Über dem Pattern gibts ein graues v1 mit Pfeil, klick darauf und Du bekommst auch eine zweite Version angeboten.
Die ist mMn. etwas unschöner, aber vielleicht hilft es um Lookaheads besser zu veranschaulichen.
Diese zweite Version dreht die Funktion vom Lookahead um.
Das "eigentliche" Pattern .{9} prüft, dass es 9 beliebige Zeichen gibt und der Lookahead prüft mit \w+\s*\.W deine Regeln.

H
HiJack82 Themenstarter:in
19 Beiträge seit 2014
vor 6 Jahren

Danke Sir Rufo. Jetzt kapiere ich auch, was der herbivore gemeint hat.
Vielen Dank!

Es ist doch immer am besten einfach die Lösung hinzuschreiben. Das kann man dann systematisch analysieren.

^(?=.{9}$)\w+\s*.W$

Jetzt habe ich noch ein Problem mit dem gesamten Ausdruck:
(Soweit ich bisher verstanden habe mit dem lookahead)

Beispiel:
START HELLO .W END
oder
START HELLO .W FINISH

Expression:
\b^START\s\b(?=.{9})\w+\s*.W\s(\bEND\b|\bFINISH\b)

Ich möchte eigentlich nur HELLO .W auf die Länge von 9 Zeichen prüfen. Das funktioniert aber mit meiner oben gezeigten Expression noch nicht richtig. Muss ich da noch ein $ setzten, oder?

Übrigens, das ^ bei START habe ich drin, weil START der erste String in der Zeile ein muss. Ohne dieses Zeichen werden führende Leerzeichen akzeptiert. Das möchte ich aber nicht. Habe ich das dann so richtig gemacht?

D
985 Beiträge seit 2014
vor 6 Jahren

@Palladin007

Bei mir ist das $ im Look-Ahead, weil dein Pattern auch abcdefg.W durchlässt (hat 10 Zeichen) und meins nicht 😁

49.485 Beiträge seit 2005
vor 6 Jahren

Hallo HiJack82,

Es ist doch immer am besten einfach die Lösung hinzuschreiben.

nö, das Forum ist kein Pattern-Generator. Du beschäftigst dich ja mit dem Lösungsweg, wie man an deinen Antworten sieht. Andere tun das nicht und wollen nur andere Leute einspannen, um ohne eigenen Aufwand eine funktionierende Lösung zu bekommen. Deshalb posten wir eben gerade nicht einfach eine fertige Lösung.

Jetzt habe ich noch ein Problem mit dem gesamten Ausdruck

Wenn vor und nach dem (Teil)String mit 9 Zeichen noch was anderes steht, dann funktioniert der Look Ahead so natürlich nicht. Der geht ja davon aus, dass von Beginn bis Ende des String (bzw. der Zeile) nur 9 Zeichen stehen.

Aber natürlich kann man den Look Ahead auch so ändern, dass er nach einem Muster einer bestimmten Länge sucht, also z.B. das was du oben (fast) geschrieben hast (leicht geändert):

(\w|\s){7}(.W)

Nur eben in den Look Ahead gepackt. Der Look Ahead sorgt dann wieder für die richtige Länge, diesmal eben von sieben(!) Zeichen (Buchstaben oder Leerzeichen). Für die richtige Reihenfolge von \w+ und \s* sorgt dann wieder der eigentliche Pattern.

herbivore

H
HiJack82 Themenstarter:in
19 Beiträge seit 2014
vor 6 Jahren

@herbivore

Andere tun das nicht und wollen nur andere Leute einspannen, um ohne eigenen Aufwand eine funktionierende Lösung zu bekommen.

Da hast Du natürlich schon recht. Aber schau mal, wie wenig Fragen ich in der langen Zeit im Forum gestellt habe. Ich gehe in der Regel immer wie folgt vor:

  • vorhandene Bücher
  • Google
  • Foren lesen
    --> Frage im Forum stellen

Manchmal steht mal halt auch bei vermeintlich einfachen Dingen so richtig auf dem Schlauch...

So wie auch ich leider immer noch 😦

Ich habe jetzt folgende Expression:
\b^START\s\b(?=(\w|\s){7})\w+\s*.W(\s)(\bEND\b|\bFINISH\b)

Die Funktioniert bis auf eine Ausnahme (hoffe es ist wirklich nur eine). Der Teilstring "HELLO .W" darf bei mit mindestens 9 Zeichen lang sein. Die maximale länge wird aber scheinbar nicht richtig geprüft. Hat jemand eine Idee, was ich an meinem Ausdruck noch verbessern kann?

49.485 Beiträge seit 2005
vor 6 Jahren

Hallo HiJack82,

es reicht natürlich nicht (\w|\s){7} in den Look Ahead zu schreiben. Das fordert ja nur, dass mindestens 7 Zeichen vorhanden sind. Es muss auch noch der Teil in der Look Ahead, der das Ende dieser 7 Zeichen markiert, also mindestens der Punkt (\.). So wie ja vorher auch das $ mit im Look Ahead stand.

herbivore

H
HiJack82 Themenstarter:in
19 Beiträge seit 2014
vor 6 Jahren

Puhh, jetzt bin ich glaube ich fertig:

So steht die Expression jetzt. Scheint jetzt auch meine Anforderungen zu erfüllen.
\b^START\s\b(?=(\w|\s){7}.W)\w+\s*.W(\s)(\bEND\b|\bFINISH\b)

Das war eine schwere Geburt. Vielen Dank an alle beteiligten.

Mit RegEx muss man sich einfach eine Weile beschäftigen. Hoffentlich gehts beim nächsten mal leiter von der Hand...