Hallo Pit,
so, bin auch wieder da. Musste in Telefonkonferenzen, dann Heimfahrt aus dem Büro, Einkaufen, Star Trek Discovery gucken, Biathlon Herrenstaffel gucken, viel zu tun 😂
Die letzte Regex die ich von Dir sehe (mit Modifikation von Jörg), ist:
/^(?<startwort>AB[\w\d]+[a-zA-Z-]*)\s+(?<startplus>(AB[\w\d-]+[,]*\s+)*)(?<vorwort>.*)\s+(?<zahl>\d+)\s+(?<wort>[a-zA-Z0-9_üöä]+)\s+(?<betrag>[\d.,]+)\s*$/
#1. (?<startwort>AB[\w\d]+[a-zA-Z-]*)
Das [a-zA-Z-]* hintendran ist sinnlos, das wird vom [\w\d]+ davor schon mit gematcht. Bring das Minus einfach in die Buchstaben/Ziffernfolge hinein. Und ich wette, dass irgendwer auch noch ein Komma hinter's Startwort gemacht hat. Und ein Ober-Experte hat garantiert noch ein Deppen-Space VOR das Komma gemacht. Oder vielleicht gar kein Space, nur ein Komma. Null Problemo, das matchen wir alles:
(?<startwort>AB[\w\d-]+)(\s*,\s*|\s+)
Liest sich so: AB, dann 1-n Buchstaben,Ziffern,Minusse, dann ENTWEDER ein durch optionale Spaces eingeschlossenes Komma ODER mindestens ein Space. Leerraum und Komma sind nicht Teil der benannten startwort-Gruppe.
#2. (?<startplus>(AB[\w\d-]+[,]*\s+)*)
Jörg hatte das [,]* empfohlen, was „am Ende 0-n Zeichen der Kategorie Komma“ bedeutet. Kann man machen, aber ich würd's so machen wie beim Startwort:
(?<startplus>(AB[\w\d-]+(\s*,\s*|\s+))*)
Hier ist der Trennbereich im startplus-Match mit drin, das lässt sich nicht vermeiden. PHP kennt keine Match-Arrays, d.h. sowas wie ((?<startplus>AB\d+)(\s*,\s*|\s+))*
würde unter startplus nicht die gefundenen Worte als Array ablegen, sondern nur das letzte startplus-Wort. Wenn du die startplus-Worte einzeln brauchst, musst Du das separat zerlegen.
#3. ABBILD
Den rauszufieseln ist kaum möglich, es sei denn, du kannst definieren, dass die Codewörter immer mindestens eine Ziffer hinter dem AB enthalten. Dann könnte man die Codewörter so matchen: statt AB[\w\d-]+
nimmt man (AB[\w\d-]*\d[\w\d-]*
Häßlichkeiten wie „AB-4711“ oder „ABB1LD-“ würden davon auch erfasst.
#4. non-capturing groups
Ein kleiner Hinweis am Rand, falls dich die unbenannten Match-Gruppen nerven. Sowas kann man abblocken, indem man hinter der öffnenden Klammer ein ?> notiert, also (?>AB\d+) statt (AB\d+).
Ich habe das alles in deine regex101 Session eingetragen: https://regex101.com/r/VcgXCb/7
#5. Wie macht man das eleganter?
Solche Regexe sind unübersichtlich und haben Teile, die sich wiederholen. Das ist lästig und bei Änderungen fehleranfällig. In PHP kann man das Pattern auch aus Teilsegmenten zusammensetzen (ich hoffe, ich vertippe mich jetzt nicht). Um die Variablen im Gewühl besser zu erkennen, würde ich hier die komplexe String-Parsing Syntax von PHP empfehlen (also geschweifte Klammern). Zumindest coloriert der PHP-Parser des Forums damit deutlich besser:
$codewort = "AB[\w\d-]*\d[\w\d-]*";
$codespace = "(?>\s*,\s*|\s+)";
$keyword = "(?<wort>[a-zA-Z0-9_üöä]+)";
$betrag = "(?<betrag>[\d.,]+)";
$pStartWort = "(?<startwort>{$codewort}){$codespace}";
$pStartPlus = "(?<startplus>(?>{$codewort}{$codespace})*)";
$pZwischenteil = "(?<vorwort>.*)\s+(?<zahl>\d+)";
$pattern = "/^{$pStartWort}{$pStartPlus}{$pZwischenteil}\s+{$keyword}\s+{$betrag}\s*$/";
Ob es Dir mit oder ohne {} besser gefällt ist deine Sache. Ich finde es {so} lesbarer.
Rolf
sumpsi - posui - clusi