Pit: Nochmal Regex gesucht

0 71

Nochmal Regex gesucht

Pit
  • regex
  1. 0
    ursus contionabundo
    1. 0
      ursus contionabundo
    2. 0
      Pit
      1. 0
        Matthias Apsel
        1. 0
          Pit
          1. 0
            ursus contionabundo
            1. 0
              Pit
              1. 0
                Rolf B
                1. 0
                  Pit
                  1. 0
                    Rolf B
                    1. 0
                      Pit
                  2. 0
                    Rolf B
                    1. 0
                      Pit
                      1. 0
                        Rolf B
                        1. 0
                          Matthias Apsel
                          1. 0
                            Pit
                            1. 0
                              Rolf B
                              1. 0
                                Pit
                                1. 0

                                  So geht es fast...

                                  Pit
                                  1. 0

                                    Diese Zeile krieg ich nicht gematcht

                                    Pit
                                    1. 0
                                      ursus contionabundo
                                      1. 0
                                        Pit
                                        1. 0
                                          Self-Nachtwächter
                                          • programmiertechnik
                                          • programmplanung
                                          • regex
                                          1. 0
                                            Rolf B
                                            1. 0
                                              Pit
                                              1. 0

                                                Lösungsalternative: pdftotext

                                                ursus contionabundo
                                          2. 0
                                            Pit
                                            1. 0

                                              Diese Zeile krieg ich nicht gematcht - weitere Vereinfachung

                                              ursus contionabundo
                                    2. 0
                                      Gunnar Bittersmann
                                      1. 0
                                        Pit
                                        1. 0
                                          Gunnar Bittersmann
                                          1. 0
                                            Pit
                                            1. 0
                                              Rolf B
                                              1. 0
                                                Pit
                                                1. 0
                                                  MudGuard
                                                2. 0
                                                  Pit
                                                  1. 1
                                                    Pit
                        2. 0
                          Pit
                        3. 0
                          Pit
                          1. 0
                            Pit
                            1. 0
                              Rolf B
                              1. 0
                                Pit
                  3. 0

                    Nach Deinen Ergänzungern verbesserte Lösung

                    ursus contionabundo
                    1. 0
                      Pit
                      1. 0
                        ursus contionabundo
                        1. 0
                          Pit
                          1. 0

                            Tips zur Fehlersuche

                            ursus contionabundo
                            • php
                            1. 0
                              Pit
                              1. 0

                                Du bist nicht allein ...

                                ursus contionabundo
                                1. 0
                                  Pit
                  4. 0
                    Gunnar Bittersmann
                    1. 0
                      Pit
                      1. 0
                        Gunnar Bittersmann
              2. 0

                Vorhersehbar untauglicher Lösungsversuch

                ursus contionabundo
              3. 0
                pl
          2. 0
            Matthias Apsel
            1. 0
              Pit
          3. 0
            beatovich
            1. 0
              Pit
      2. 0
        pl
        1. 0
          Pit
          1. 0
            Mitleser
            • meinung
            • regex
          2. 0
            pl
            1. 0
              Rolf B
              1. 0
                pl
                1. 0
                  Rolf B
                  1. 0
                    pl
            2. 0
              Gunnar Bittersmann
      3. 0
        dedlfix
        1. 0
          Pit

Hallo Forum,

diesmal eine etwas kompliziertere Geschichte…

Ich habe eine Textzeile, in der ein bestimter String "XYZ" oder "ABC" oder "Trallala" als ganzes Wort vorkommt. Vor diesem String steht immer ein Leerzeichen und davor eine Zahl, die aus n Ziffern besteht. Begrenzt in Richting Zeilenanfang wird diese Zahl wieder durch ein Leerzeichen. Hinter dem String steht (nach dem Leereichen) ein Betrag (mit Tausendepunkt und Komma). Diese Zahl bildet auch zugleich das Zeilenende.

Ich benötige sowohl den String selber als auch die Zahl als auch den Betrag.

Kann man das überhaupt über eine einzige Regex ermitteln?

Nochmal danke für Eure Hilfe.

Pit

  1. Ich benötige sowohl den String selber als auch die Zahl als auch den Betrag.

    Kein Problem. In welcher Programmiersprache?

    1. Ich benötige sowohl den String selber als auch die Zahl als auch den Betrag.

      Kein Problem. In welcher Programmiersprache?

      In php. Aber ist das für die (ggf.) Regex denn wichtig?

      Pit

      1. Hallo Pit,

        Ich benötige sowohl den String selber als auch die Zahl als auch den Betrag.

        Kein Problem. In welcher Programmiersprache?

        Aber ist das für die (ggf.) Regex denn wichtig?

        Für den Regex vielleicht weniger aber für „benötigen“ und „Betrag“.

        Bis demnächst
        Matthias

        --
        Pantoffeltierchen haben keine Hobbys.
        1. Hallo Matthias,

          Aber ist das für die (ggf.) Regex denn wichtig?

          Für den Regex vielleicht weniger aber für „benötigen“ und „Betrag“.

          Versteh ich nicht. Ich habe aus meiner ersten Regex einen Vorschlag gemacht, den ich mir selber zusammengewerkelt hatte. Und auch bei sonstigen Anfragen habe ich meist meine eigene Lösung als Ausgangspunkt meiner Frage zur Diskussion gestellt. Ich versuche grundsätzlich auf jede Antwort einzugehen, ich beteilige mich so gut es geht, den Lösungsweg mitzugestalten und ich bedanke mich bei jedem, der mir hilft. Ich sollte also hier bisher nicht als jemand aufgetreten sein, der das Forum und seine Helfer als "Lösungslieferanten" ansieht. Bei der Erarbeitng einer Regex sind glasklare Vorgaben wichtig, wie ich in meinem ersten Thread hierzu gelernt habe, daher meine Formulierung "Ich habe, ich such, ich benötige"...das war keine Aufforderung an Euch, sondern meine Problembeschreibung.

          Und meine Frage bezieht sich doch erstmal "nur" darauf, zu ermitteln, ob ich bei meiner Problemstellung mit einer Regex auf dem richtigen Weg bin oder ob ich mehrere Ausdrücke, ggf. gar im Zusammenspiel mit einer Programmier-/Scriptsprache brauche.

          Ist denn mein Ausgangspost frech oder fordernd 'rübergekommen? So wars nämlich nicht gemeint.

          Oder habe ich sonst was falsch gemacht? Wie gesagt, ich versteh grad nicht, was Du/Ihr meint, daher die Nachfrage. Wenn etwas falsch war, kann ich das ja vielleicht künftig besser machen.

          Pit

          1. Heheh Pit. Ruhig mit den Pferden. Ohne Rückfragen geht es halt manchmal nicht.

            Ich versuche jetzt im zweiten Schritt (PHP und preg_match() ist ja nun klar) mal herauszubekommen, was Du mit diesem Durcheinander

            Ich habe eine Textzeile, in der ein bestimter String "XYZ" oder "ABC" oder "Trallala" als ganzes Wort vorkommt. Vor diesem String steht immer ein Leerzeichen und davor eine Zahl, die aus n Ziffern besteht. Begrenzt in Richting Zeilenanfang wird diese Zahl wieder durch ein Leerzeichen. Hinter dem String steht (nach dem Leereichen) ein Betrag (mit Tausendepunkt und Komma). Diese Zahl bildet auch zugleich das Zeilenende.

            gemeint hast. Ist:

            • Zeilenanfang
            • beliebiges Zeug
            • Leerzeichen
            • eine Zahl, die aus n Ziffern besteht. (Ist n fix, z.B. immer 8?)
            • Leerzeichen
            • gesuchter, genau bestimmter String
            • Leerzeichen
            • ein Betrag (mit Tausenderpunkt und Komma)
            • Zeilenende

            richtig? Meinst Du mit "Komma" wirklich ein Komma oder einen Punkt als Dezimaltrenner?

            1. Heheh Pit. Ruhig mit den Pferden. Ohne Rückfragen geht es halt manchmal nicht.

              Alles gut, ich war nicht sicher, ob meine Frage unhöflich 'rüberkam. Daher wollte ich es erklären.

              was Du mit diesem Durcheinander

              Wenn man Beispieldaten hat, wird es sicher deutlicher.

              Ich habe eine Textzeile, in der ein bestimter String "XYZ" oder "ABC" oder "Trallala" als ganzes Wort vorkommt. Vor diesem String steht immer ein Leerzeichen und davor eine Zahl, die aus n Ziffern besteht. Begrenzt in Richting Zeilenanfang wird diese Zahl wieder durch ein Leerzeichen. Hinter dem String steht (nach dem Leereichen) ein Betrag (mit Tausendepunkt und Komma). Diese Zahl bildet auch zugleich das Zeilenende.

              Beispieldaten:

              AB0006777 Lore Ipsum 25 ABC 3,72

              AB09899 AB00067127 At vero, eos et 2 1 XYZ 13,11

              AB0007711 CD0TZUUZ AB899979 At vero eos et 10 100 XYZ 1.223,50

              In Zeile 1 suche ich: Lore Ipsum; 25;ABC;3,72

              In Zeile 2 suche ich: At vero, eos et 2;1;XYZ;13,11

              In Zeile 3 suche ich: At vero eos et 10;100;XYZ;1.233,50

              Hintergrund ist, aus einem unsortierten Datenhaufen eine sortierte Tabelle oder csv zu machen.

              Pit

              1. Hallo Pit,

                deine urspüngliche Beschreibung und deine Erklärung, welche Fragmente Du aus deinen Beispielen herausgeholt haben willst, passen nicht zusammen. Dass vor der "durch Leerzeichen begrenzten Zahl" weiterer Text kommt, der aus Buchstaben, Leerzeichen unter Interpunktion bestehen kann, hast Du bisher nicht erwähnt.

                Du hast also ab Zeilenanfang 1-N "Wörter", die aus 2 Buchstaben und 1-n weiteren Zeichen (Buchstaben und Ziffern) bestehen. Diese Wörter sind durch Leerzeichen begrenzt. (AB09899, CD0TZUUZ). Diese Wörter interessieren Dich nicht.

                Dann folgt Text, bestehend aus Wörtern in Groß- und Kleinschrift und Satzzeichen. Auch Zahlen können in diesem Text vorkommen, sogar am Ende (At vero eos et 10). Diesen Text möchtest Du haben, inclusive der Zahlen.

                Dann kommt eine Leerstelle, eine Integerzahl und noch eine Leerstelle. Du möchtest die Integerzahl haben.

                Es folgt dein ABC oder XYZ Wort, dann wieder eine Leerstelle. Du willst das Wort.

                Schließlich folgt ein Betrag mit einem Tausenderpunkt und einem Dezimalkomma. Vielleicht noch etwas Whitespace - wer weiß. Dann endet die Zeile. Du möchtest den Betrag haben.

                Richtig?

                Rolf

                --
                sumpsi - posui - clusi
                1. Hallo Rolf,

                  deine urspüngliche Beschreibung und deine Erklärung, welche Fragmente Du aus deinen Beispielen herausgeholt haben willst, passen nicht zusammen. Dass vor der "durch Leerzeichen begrenzten Zahl" weiterer Text kommt, der aus Buchstaben, Leerzeichen unter Interpunktion bestehen kann, hast Du bisher nicht erwähnt.

                  Echt nicht? Oh...

                  Du hast also ab Zeilenanfang 1-N "Wörter", die aus 2 Buchstaben und 1-n weiteren Zeichen (Buchstaben und Ziffern) bestehen. Diese Wörter sind durch Leerzeichen begrenzt. (AB09899, CD0TZUUZ). Diese Wörter interessieren Dich nicht.

                  Anders... die habe ich schon, daher interessieren sie mich jetzt nicht weiter.

                  Dann folgt Text, bestehend aus Wörtern in Groß- und Kleinschrift und Satzzeichen. Auch Zahlen können in diesem Text vorkommen, sogar am Ende (At vero eos et 10). Diesen Text möchtest Du haben, inclusive der Zahlen.

                  Dann kommt eine Leerstelle, eine Integerzahl und noch eine Leerstelle. Du möchtest die Integerzahl haben.

                  Es folgt dein ABC oder XYZ Wort, dann wieder eine Leerstelle. Du willst das Wort.

                  Schließlich folgt ein Betrag mit einem Tausenderpunkt und einem Dezimalkomma. Vielleicht noch etwas Whitespace - wer weiß. Dann endet die Zeile. Du möchtest den Betrag haben.

                  Richtig?

                  Nkicht ganz, denn das kann auch anders sein, daher würde ich das Pferd gerne von hinten aufzäumen.

                  Was immer stimmt, ist nur:

                  • Der Betrag steht immer am Ende der Zeile.
                  • Mein ABC oder XYZ Wort steht immer durch Leerzeichen getrennt vor dem Betrag.
                  • Die Zahl, die ich auch benötige, steht immer durch Leerzeichen getrennt vor dem ABC-/XYZ-Wort
                  • Alles was dann noch durch Leerzeichen getrennt links vor dem ABC-/XYZ-Wort steht brauche ich genau bis zum letzten Vorkommen plus Stringlänge eines Ausdrucks, der mit AB anfängt und dann ein weiteres Zeichen (Buchstabe oder Ziffer) hat und anschließend eine oder beliebig viele Ziffern bis zu einem Leerzeichen enthält. Diese Stelle habe ich aber bereits ermittelt.

                  Pit

                  1. Hallo Pit,

                    Diese Stelle habe ich aber bereits ermittelt.

                    Ok, dafür kannst Du den offset-Parameter von preg_match verwenden, dann fängt er erst da an zu suchen. Das hättest Du aber bei deinen Beispielen dazu schreiben müssen.

                    Alles was dann noch durch Leerzeichen getrennt links vor dem ABC-/XYZ-Wort steht brauche ich genau bis zum letzten Vorkommen plus Stringlänge eines Ausdrucks, der mit AB anfängt und dann ein weiteres Zeichen (Buchstabe oder Ziffer) hat und anschließend eine oder beliebig viele Ziffern bis zu einem Leerzeichen enthält.

                    Rhabarber Rhabarber Rhabarber? WAS BRAUCHST DU? Ab wo bis wo? Es passt WIEDER nicht zu dein Beispielen. Oder ich bin doof.

                    $brain->reset()

                    Nehmen wir nochmal das Beispiel 3 her:

                    AB0007711 CD0TZUUZ AB899979 At vero eos et 10 100 XYZ 1.223,50
                    0....:....1....:....2....:....3
                    

                    Die 3 "Worte" zu Beginn hast Du bereits ermittelt. D.h. du weißt, dass der Text, der dich interessiert, ab Position 28 beginnt.

                    Alles was ... links vor dem ABC-/XYZ-Wort steht brauche ich bis zum (unverständliches Kauderwelsch)

                    Ich unterstelle mal, dass das Kauderwelsch nichts anderes ist als "ich will das, was (im Beispiel 3) vor Position 28 steht, nicht mehr haben". Ok. Dafür gibt's den offset-Parameter von preg_match. Und Du willst nicht "alles links vom ABC Wort", sondern alles außer der Zahl, die links vom ABC-Wort steht, oder? Die Zahl hattest Du ja schon separat beschrieben. Demnach müsste es so passen:

                    $pattern = "/(?<vorwort>.*)\s+(?<zahl>[0-9]+)\s+(?<wort>[A-Z]+)\s+(?<betrag>[0-9.,]+)\s*$/";
                    if (preg_match($pattern, $line, $matches, 0, $offset) == 1) {
                       echo "Text zu Beginn   : $matches[vorwort]<br>";
                       echo "Zahl vor Suchwort: $matches[zahl]<br>";
                       echo "Gesuchtes Wort   : $matches[wort]<br>";
                       echo "Betrag           : $matches[betrag]<br>";
                    }
                    

                    Das Pattern verwendet benannte Gruppen (?<name>...), damit Du die gefundenen Fragmente im $matches-Array leicht finden kannst. Ich bin ziemlich grob beim Matchen des Betrags, aber ich denke, du hast plausible Daten und brauchst keine exakte Kontrolle auf Richtigkeit.

                    Elemente des Patterns sind:

                    (?<vorwort>.*)\s+ Beliebige Zeichen, und am Ende 1-n Leerstellen

                    (?<zahl>[0-9]+)\s+ eine Zahl aus 1-n Ziffern 0-9, dann 1-n Leerstellen

                    (?<wort>[A-Z]+) Dein gesuchtes Wort, aus Buchstaben A-Z. Keine Kleinbuchstaben, keine Umlaute, wenn das nicht passt musst Du hier nachbessern. Ob Du da in die Verlegenheit kommst, wilde Akzentzeichen oder Zeichen aus nicht-deutschen Sprachen zu finden, weiß ich nicht. Das weißt Du.

                    (?<betrag>[0-9.,]+) Der Betrag, als Zeichenkette aus Ziffern, Punkt und Komma. Wie gesagt, das ist ein grober Match. Er matcht auch Beträge die falsches Format haben. Solange deine Daten nur valide Beträge enthalten, reicht das.

                    \s$ Zum Schluss noch verirrte Leerstellen überspringen und das Zeilenende matchen. Dadurch wird der gewünschte "von hinten" Effekt erreicht.

                    Rolf

                    --
                    sumpsi - posui - clusi
                    1. Hallo Rolf,

                      Rhabarber Rhabarber Rhabarber? WAS BRAUCHST DU? Ab wo bis wo? Es passt WIEDER nicht zu dein Beispielen. Oder ich bin doof.

                      Haha... ich glaub, ich würd auch bekloppt, wenn ich mein Geschreibsel lesen würde, aber inhaltlich ist es leider vollkommen korrekt 😉

                      Nehmen wir nochmal das Beispiel 3 her:

                      AB0007711 CD0TZUUZ AB899979 At vero eos et 10 100 XYZ 1.223,50
                      0....:....1....:....2....:....3
                      

                      Die 3 "Worte" zu Beginn hast Du bereits ermittelt. D.h. du weißt, dass der Text, der dich interessiert, ab Position 28 beginnt.

                      Ja, stimmt genau.

                      Alles was ... links vor dem ABC-/XYZ-Wort steht brauche ich bis zum (unverständliches Kauderwelsch)

                      😀

                      Ich unterstelle mal, dass das Kauderwelsch nichts anderes ist als "ich will das, was (im Beispiel 3) vor Position 28 steht, nicht mehr haben". Ok. Dafür gibt's den offset-Parameter von preg_match. Und Du willst nicht "alles links vom ABC Wort", sondern alles außer der Zahl, die links vom ABC-Wort steht, oder? Die Zahl hattest Du ja schon separat beschrieben. Demnach müsste es so passen:

                      $pattern = "/(?<vorwort>.*)\s+(?<zahl>[0-9]+)\s+(?<wort>[A-Z]+)\s+(?<betrag>[0-9.,]+)\s*$/";
                      if (preg_match($pattern, $line, $matches, 0, $offset) == 1) {
                         echo "Text zu Beginn   : $matches[vorwort]<br>";
                         echo "Zahl vor Suchwort: $matches[zahl]<br>";
                         echo "Gesuchtes Wort   : $matches[wort]<br>";
                         echo "Betrag           : $matches[betrag]<br>";
                      }
                      

                      Uff, ich bin geplättet! Wahnsinn... ganz ehrlich. Ich hätte nicht gedacht, dass das wirklich in einem einzigen Ausdruck machbar ist. Und dann noch so komfortabel in ein assoziatives array abgelegt. Hut ab, das ist große Klasse. Du hast Recht, ich muß noch ein bißchen feinjustieren, aber das macht keine Probleme. Danke auch für die Erklärung im Anhang, die ist für mich sehr sinnvoll.

                      Ich hätte ohne Hilfe wirklich versucht, diese Dinge nacheinander Stück für Stück zu ermitteln. Das ist auch der Grund, warum ich das Offset bereits kenne. in Wirklichkeit variiert das natürlich auch gewaltig.

                      Wäre das auch möglich gewesen, in Deine Regex auch noch zu übernehmen?

                      Wie gesagt, es ist nicht wirklich nötig, ich komme auch ohne zurecht. Es interessiert mich nur.

                       AB0007711 CD0TZUUZ AB899979 At vero eos et 10 100 XYZ 1.223,50
                       0....:....1....:....2....:....3
                      

                      In dieser Zeile muß ich das den ersten Ausdruck ermitteln, eigentlich das erste Wort bis zum Leerzeichen. Es ist aber immer so, dass der Ausdruck /AB\w\d+\b/ oder auch /AB[a-zA-Z]?\d*\s/ passen würde. Diesen Ausdruck benötige ich auch selber, also nicht nur die Position, also zb. $matches[erster]="AB0007711";

                      Die (in diesem Beispiel) nachfolgenden Ausdrücke (CD0TZUUZ AB899979) sind optional vorhanden, d.h. mal gibt es einen hiervon, mal 2, 3 oder n davon. Aber die entsprechen ebenfalls immer /AB\w\d+\b/ oder auch /AB[a-zA-Z]?\d*\s/ (auch, wenn das in obigem Beispiel nicht so ist, da ist einfach der Beispieldatensatz nicht ganz korrekt). Hier bräuchte ich alle Ausdrücke in einer Variable, also zb. $matches[zweiter]="CD0TZUUZ AB899979";

                      Aber nochmal: Gerade, nachdem ich Deinen Zusatz zur antwort gelesen habe, brauche ich das nicht mehr wirklich, es ingteressiert mich nur, ob das auch gegangen wäre. 😀

                      Pit

                  2. Hallo Pit,

                    kleiner Nachtrag. Wenn Du Spaß dran hast, kannst Du die Startworte auch im Pattern mit überspringen. Das sähe so aus:

                    ^(?<startworte>(([A-Z][A-Z][A-Z0-9]+)\s+)+)(?<vorwort>.*)\s+(?<zahl>[0-9]+)\s+(?<wort>[A-Z]+) (?<betrag>[0-9.,]+)\s*$
                    

                    Das Pattern unterstellt, dass es 1-n Startworte gibt, die jeweils aus zwei Buchstaben und dann einer wilden Mischung aus Buchstaben und Ziffern bestehen. Wenn "Buchstabe" weiter zu fassen ist als A-Z, musst Du das Pattern natürlich erweitern.

                    Rolf

                    --
                    sumpsi - posui - clusi
                    1. Hallo Pit,

                      kleiner Nachtrag. Wenn Du Spaß dran hast, kannst Du die Startworte auch im Pattern mit überspringen. Das sähe so aus:

                      ^(?<startworte>(([A-Z][A-Z][A-Z0-9]+)\s+)+)(?<vorwort>.*)\s+(?<zahl>[0-9]+)\s+(?<wort>[A-Z]+) (?<betrag>[0-9.,]+)\s*$
                      

                      Das Pattern unterstellt, dass es 1-n Startworte gibt, die jeweils aus zwei Buchstaben und dann einer wilden Mischung aus Buchstaben und Ziffern bestehen. Wenn "Buchstabe" weiter zu fassen ist als A-Z, musst Du das Pattern natürlich erweitern.

                      Hi Rolf,

                      das ist lustig, ich antworte Dir gerade auf Deine Megalösung und frage fast genau danach 😉

                      Also...Antwort folgt, sie ist schon halb fertig.

                      Pit

                      sumpsi - posui - clusi

                      1. Hallo Pit,

                        ich sehe das nicht so negativ wie Jörg (ursus fastixiabundo :) ).

                        Wenn Du die einleitenden Codes separat haben willst, kannst Du das so machen:

                        /^(?<startwort>AB[\w\d]+)\s+(?<startplus>(AB[\w\d]+\s+)+)(?<vorwort>.*)\s+(?<zahl>\d+)\s+(?<wort>\w+)\s+(?<betrag>[\d.,]+)\s*$/
                        

                        Ich habe mal deine Aussage eingebaut, dass die Codewörter am Zeilenanfang immer mit AB starten. Und ich habe auf \w und \d umgestellt, statt [A-Z] und [0-9]. Ist vermutlich besser so. Es matcht dann auf jeden Fall auch die Kleinbuchstaben, und je nach locale-einstellungen auf deinem Server auch Akzentzeichen (áàâä und Familie)

                        Zerlegt in die einzelnen Teile:

                        ^                                  Zeilenstart
                        (?<startwort>AB[\w\d]+)            Erstes AB238423 Wort -> $matches['startwort']
                        \s+                                Leerraum
                        (?<startplus>(AB[\w\d]+\s+)+)      1-N AB293482309 Worte -> $matches['startplus']
                        (?<vorwort>.*)                     Freitext -> $matches['vorwort']
                        \s+                                Leerraum
                        (?<zahl>\d+)                       Int-vor dem letzten Wort -> $matches['zahl']
                        \s+                                Leerraum
                        (?<wort>\w+)                       letztes Wort -> $matches['wort']
                        \s+                                Leerraum
                        (?<betrag>[\d.,]+)                 Betrag -> $matches['betrag']
                        \s*                                optionaler Leerraum
                        $                                  Zeilenende
                        

                        Für mich ist bei solchen Aufgaben die Seite regex101.com sehr hilfreich. Da bekommst Du erklärt, was die Regex tut, und kannst sie ausprobieren.

                        Rolf

                        --
                        sumpsi - posui - clusi
                        1. Hallo Rolf B,

                          Und ich habe auf \w und \d umgestellt, statt [A-Z] und [0-9]. Ist vermutlich besser so. Es matcht dann auf jeden Fall auch die Kleinbuchstaben, und je nach locale-einstellungen auf deinem Server auch Akzentzeichen (áàâä und Familie)

                          Meines Wissens gilt

                          \w = [a-zA-Z0-9_]

                          Bis demnächst
                          Matthias

                          --
                          Pantoffeltierchen haben keine Hobbys.
                          1. Meines Wissens gilt

                            \w = [a-zA-Z0-9_]

                            Stimmt, Matthias. Ich habs überprüft, das muß ich feinjustieren. Aber insgesamt ist diese Regex der Hammer.

                            Pit

                            1. Hallo Pit,

                              php.net schreibt:

                              A "word" character is any letter or digit or the underscore character, that is, any character which can be part of a Perl "word". The definition of letters and digits is controlled by PCRE's character tables, and may vary if locale-specific matching is taking place. For example, in the "fr" (French) locale, some character codes greater than 128 are used for accented letters, and these are matched by \w.

                              Rolf

                              --
                              sumpsi - posui - clusi
                              1. Hi Rolf,

                                ich habe noch eine Frage, weil relevant:

                                Im Datensatz steht meistens im "Startplus" ein Komma, also:

                                AB0007711 AB0TZUUZ, AB899979 At vero eos et 10 25 XYZ 1.223,50

                                Hierdurch wird der Eintrag von "Startplus" ins "Text zu Beginn" verschoben.

                                Es gelingt mir aber grad nicht, das zu korrigieren.

                                Wie mache ich das?

                                Pit

                                1. ich habe noch eine Frage, weil relevant:

                                  Im Datensatz steht meistens im "Startplus" ein Komma, also:

                                  AB0007711 AB0TZUUZ, AB899979 At vero eos et 10 25 XYZ 1.223,50

                                  Hierdurch wird der Eintrag von "Startplus" ins "Text zu Beginn" verschoben.

                                  Es gelingt mir aber grad nicht, das zu korrigieren.

                                  Wie mache ich das?

                                  Ich hatte schonmal an:

                                  ^(?<startwort>AB[\w\d]+)\s+(?<startplus>(AB[\w\d]+[,]*\s+)*)(?<vorwort>.*)\s+(?<zahl>\d+)\s+(?<wort>\w+)\s+(?<betrag>[\d.,]+)\s*$
                                  

                                  gedacht, aber das verschiebt mir zwar das AB0TZUUZ, AB899979 wieder in die Startplus-Gruppierung, generiert mit aber eine Gruppe3 hinzu, in der auch nochmal die letzte AB-Zahl drin steht.

                                  Pit

                                  1. Hallo,

                                    diese Zeile bekomme ich nicht gematcht, jedenfalls nicht so, dass die richtigen Ausdrücke in den Arrayelementen landen.

                                    Wie macht man das, ich habe alles versucht (jedenfalls die Sachen, die nicht zum Erfolg führen ;) )

                                    Die Fallstricke hierbei sind:

                                    • Das -Q im Startplus
                                    • Das AB... im Vorwort

                                    Pit

                                    1. /^(?<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*$/
                                      

                                      Die Änderung:

                                      ALT: <startplus>(AB[\w\d]+[,]*\s+)
                                      NEU: <startplus>(AB[\w\d-]+[,]*\s+)
                                      

                                      Test

                                      1. Hi ursus,

                                        Die Änderung:

                                        ALT: <startplus>(AB[\w\d]+[,]*\s+)
                                        NEU: <startplus>(AB[\w\d-]+[,]*\s+)
                                        

                                        Test

                                        Erstmal danke für die späte Hilfe. Leider ist das ergebnis nicht ganz korrekt, denn das Wort ABBILD gehört eigentlich in die "Group: vorwort", es steht aber in der "Group: startplus"

                                        Pit

                                        1. "startplus"

                                          War mal so definiert:

                                          mit AB anfängt und dann ein weiteres Zeichen (Buchstabe oder Ziffer) hat und anschließend eine oder beliebig viele Ziffern bis zu einem Leerzeichen enthält.

                                          Inzwischen kam hinzu, dass nach den Ziffern auch noch "-Q" und "-QR" und dann auch ein Komma folgen kann.

                                          Ich habe das etwas vereinfacht: Regex

                                          Bevor ich weitere konstruiere, weil nachfolgend weitere Abweichler erkannt werden:

                                          1. Alle Regeln auf den Tisch!
                                          2. Es muss doch eine Quelle für diese Daten geben. Warum zum Teufel baut man aus Daten erst einen String mit Leerzeichen als Trenner, der Tupel enthält, die selbst wieder Leerzeichen enthalten um sich dann mit viel Arbeit und Rechenleistung Regelsätze bauen zu wollen, die DIESEN MIST auseinanderklamüsern sollen und dabei nicht mal alle Daten kennt. Was dazu führt, dass die Beschreibungen und also die Regexe immer neu angepasst werden müssen. Das wohl auch jedes Mal, wenn mal neue Daten kommen. ALSO: Zurück zur Quelle und dann DATEN exportieren statt MÜLL
                                          3. Das ist wie beim Autofahren. Baut man Mist wird es teuer. Die vorliegenden "Daten" sind so ein Unfall.
                                          1. Hallo Self-Nachtwächter,

                                            willkommen in der Wirklichkeit. Es gibt einfach Datenbestände, die - zumeist wegen manueller Erfassung durch kreative „Künstler“ - vermüllt sind und kein Original haben, von dem man eine bessere Fassung ableiten könnte. Die Daten sind einfach so erfasst worden, von mehreren Leuten, die unterschiedliche Vorstellungen von richtig und falsch hatten, gerne über viele Jahre hinweg, gerne auch mal mit verrutschten Spalten bei der Erfassung.

                                            Zumindest stellt sich mir Pits Problem so dar. Er versucht jetzt, das beste draus zu machen und die Daten zu sanieren. Solchen Schwierigkeiten habe ich in meiner Berufspraxis mehr als einmal gegenüber gestanden. Wenn man versucht, solche Datengebilde zu restrukturieren, entstehen genau die beschriebenen Sonderfälle. Man guckt sich die Daten an, entwickelt eine Strategie wie man sortieren könnte, probiert aus, fällt auf die Nase, probiert neu, etc.

                                            Deine Forderungen sind ein schöner Wunsch und Pit wäre sicher froh, wenn er diese Forderungen erfüllen könnte. Denn dann hätte er sein Problem gelöst.

                                            Rolf

                                            --
                                            sumpsi - posui - clusi
                                            1. Hallo Rolf, hallo Nachtschwärmer,

                                              willkommen in der Wirklichkeit. Es gibt einfach Datenbestände, die - zumeist wegen manueller Erfassung durch kreative „Künstler“ - vermüllt sind und kein Original haben, von dem man eine bessere Fassung ableiten könnte. Die Daten sind einfach so erfasst worden, von mehreren Leuten, die unterschiedliche Vorstellungen von richtig und falsch hatten, gerne über viele Jahre hinweg, gerne auch mal mit verrutschten Spalten bei der Erfassung.

                                              Oder es gibt ein Original hierzu, dass aus welchen Gründen auch immer, nicht zugänglich ist und das Einzige, was zugänglich ist, ist der Datenmüll. und da dieser seit Jahren das Einzige ist, was zugänglich ist, wird sich nun immer und immer wieder bei Bedarf aus diesem Topf bedient. Ich kenne Beides, in diesem Fall ist es noch viel einfacher. Das einzige zugängliche Dokument ist ein PDF, aus dem man sich die Daten (wenigstens) textbasiert herausziehen kann. Dabei entsteht dieses unbequeme Konstrukt. Sämtliche Versuche, das PDF zu konvertieren, generieren noch viel mehr Datenmüll. Ich hatte aber auch schon Daten, die mir in einem 450x150x150 mm großem Holzkasten, gefüllt mit einer Unmenge an Karteikarten geliefert wurden. Auf diese hatten über Jahre hinweg verschiedenste Leute die Informationen so niedergeschrieben, wie sie es für sich und die jeweils aktuelle Situation als günstig erachteten. Was ich damit sagen will: Rolf hat Recht, das ist die Realität.

                                              Zumindest stellt sich mir Pits Problem so dar. Er versucht jetzt, das beste draus zu machen und die Daten zu sanieren. Solchen Schwierigkeiten habe ich in meiner Berufspraxis mehr als einmal gegenüber gestanden. Wenn man versucht, solche Datengebilde zu restrukturieren, entstehen genau die beschriebenen Sonderfälle. Man guckt sich die Daten an, entwickelt eine Strategie wie man sortieren könnte, probiert aus, fällt auf die Nase, probiert neu, etc.

                                              Ich hätte es nicht besser ausdrücken können. Und ganz ehrlich, diese vorliegenden Daten gehen wirklich noch, ich hatte schon Excel-Tabellen, die weitaus desaströser waren als diese Daten, die ich nun habe.

                                              Deine Forderungen sind ein schöner Wunsch und Pit wäre sicher froh, wenn er diese Forderungen erfüllen könnte. Denn dann hätte er sein Problem gelöst.

                                              Absolut, aber ich/wir sind wirklich ganz knapp davor. Im Grunde sinds jetzt schon nur noch eine Handvoll Ausnahmen, die man auch bequem per Hand aussortieren könnte.

                                              Pit

                                              1. Sämtliche Versuche, das PDF zu konvertieren, generieren noch viel mehr Datenmüll.

                                                Ich sags mal so:

                                                Wenn das PDF (z.B. aus LaTeX oder dvi) generiert (nicht mit einem Treiber als Grafik pder Postscript/PS gedruckt oder vom Faxserver aus einem Tiff umgewandelt wurde ) wurde, unverschlüsselt ist und Tabellen enthält, dann habe ich mit pdftotex gute Erfahrungen gemacht.

                                                1. Versuch

                                                pdftotext -nopgbrk -layout datei.pdf datei.layout.txt
                                                

                                                2. Versuch

                                                pdftotext -nopgbrk datei.pdf datei.zeilen.txt
                                                

                                          2. Hallo Nachtwächter,

                                            danke für Deine Hilfe. Leider matcht Deine Regex zwar den zuvor genannten Ausdruck korrekt, aber z.b. folgenden nicht mehr: AB2001482 ABC0783714, AB0783714-QR, ABBILD NRRHLAT 10 XäZ 207,25, denn da legt sie die Teile falsch ab.

                                            Zu den Daten habe ich auch geantwortet.

                                            Pit

                                            1. Der 3. Versuch entspricht fast meinen ersten Vorschlägen.

                                              Ursprünglich hast Du auch weniger gesucht. Daten, die man nicht will, auch nicht aufzudröseln, macht es einfacher.

                                    2. @@Pit

                                      diese Zeile bekomme ich nicht gematcht

                                      Es war bislang nicht gesagt, dass bei den AB-Dingern hinter den Ziffern noch ‚-Q‘ stehen darf. Was hältst du den noch für Überraschungen parat?

                                      LLAP 🖖

                                      --
                                      „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
                                      1. Hi Gunnar,

                                        Es war bislang nicht gesagt, dass bei den AB-Dingern hinter den Ziffern noch ‚-Q‘ stehen darf. Was hältst du den noch für Überraschungen parat?

                                        Falsch, nicht ich halte Überraschungen parat, sondern die Daten, die - einmal in Excel o.ä. eigelesen, ihre Überraschungen erst preisgeben.

                                        In der unsortierten Textdatei ist das unmöglich zu erkennen, in der (in meinem Fall) .ods Datei in OO sieht man es aber sofort.

                                        Insofern: Ja, Du hast Recht, dass ich das nie erwähnt hatte, aber zu meiner Verteidigung sei gesagt, dass das für mich selber zu jenem Zeitpunkt nicht ersichtlich war.

                                        Pit

                                        1. @@Pit

                                          Insofern: Ja, Du hast Recht, dass ich das nie erwähnt hatte

                                          Das wäre jetzt ein guter Zeitpinkt gewesen zu sagen, was denn bei den AB-Dingern hinter den Ziffern noch stehen darf. Ein Bindestrich und ein beliebiges Zeichen? AB.\d+(?:-.)

                                          LLAP 🖖

                                          --
                                          „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
                                          1. Hi Gunnar,

                                            Das wäre jetzt ein guter Zeitpinkt gewesen zu sagen, was denn bei den AB-Dingern hinter den Ziffern noch stehen darf. Ein Bindestrich und ein beliebiges Zeichen? AB.\d+(?:-.)

                                            Bisher weiß ich: Ein Bindestrich und ein oder mehrere Buchstaben (groß/klein). Sollte nachher doch noch 'was anderes herauskommen, was möglich wäre, werde ichs aber verschweigen, sonst reißt Du mir ja den Kopf ab... 😜

                                            Spaß beiseite, mir ist bisher nur das -Q und irgendwo ein -QR aufgefallen 😀

                                            Davon abgesehen... es sind wirklich nur eine Handvoll Ausnahmen, deren manuelle Beseitigung weit wenigser Mühe machen würde, als die Regex feinzujustieren...aber ich lerne gerade wirklich viel dabei, wie ich finde. Daher meine Hartnäckigkeit...ich habe mich da jetzt wirklich reingefressen und kriegs doch alleine nicht hin.

                                            Pit

                                            1. 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
                                              1. Hallo Rolf,

                                                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 😂

                                                Ja, das kann ich natürlich verstehen 😀 Ich hatte auch schon gestern abend gesehen, dass der Reiter neue Antworten anzeigte, aber da ich über diesen Rechner grad Pastewka über meine Vu+ auf den Familien-TV streamte, konnte ich erst heute morgen in Eure Antworten hinein schauen.

                                                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*$/
                                                

                                                Ich muß Jörg da in Schutz nehmen, von ihm kommt die -Erweiterung im <startwort>, der Rest ist auf meine Versuche zurückzuführen.

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

                                                Hm... ist das so richig? Ich suche: AB, dann 0 bis n Buchstaben, gefolgt von 1-n Ziffern, gefolgt von 0 bis n Buchstaben,Ziffern,Minusse... So vielleicht: (?<startwort>AB[\w]*[\d-]+[-\w]*)(\s*,\s*|\s+) Allerdings generiert der Online-Regtester bei mir dann wieder eine Gruppe2 😟 Ich finde diesen Ausdruck, so er denn korrekt ist, weniger gierig.

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

                                                Zum einen dieselbe Frage wie oben schon: Soll ich den weniger gierigen Ausdruck verwenden? Und zum zweiten: nein, ich brauche die unter startplus gefundenen Wörter definitiv nicht einzeln, die Gruppe reicht völlig aus.

                                                #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-]*

                                                Die AB-Wörter haben immer nach dem 3.Zeichen eine oder mehrere Ziffern. Das 3. zeichen kann wahlweise auch ein Buchstabe sei (aber kein Minus o.ä.), aber ab dem 4. Zeichen kommen erstmal 1-n Ziffern, bevor dann 0-n Minusse,Buchstaben,Ziffern folgen können.

                                                Häßlichkeiten wie „AB-4711“ oder „ABB1LD-“ würden davon auch erfasst.

                                                Stimmt, aber nach der Information oben nun nicht mehr.

                                                #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+).

                                                Eigentlich nerven die mich gar nicht so sehr, ich hatte es nur angemerkt, dass die entstehen. Ich konnte damit nichts anfangen.

                                                Ich habe das alles in deine regex101 Session eingetragen: https://regex101.com/r/VcgXCb/7

                                                Sehr, sehr cool! Aber ich sagte ja bereits... der helle wahnsinn! 😀

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

                                                Ja, so ist es wirklich viel lesbarer... aber ich habe den Online-Regtester durchaus schätzen gelernt. Und da müßte ich mir dann jedesmal die Regex hieraus wieder zusammenschustern, oder?

                                                Pit

                                                1. Hi,

                                                  (?<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.

                                                  Um Teile zusammenzufassen, aber keine Gruppe zu erzeugen: (?:irgendwas) statt (irgendwas)

                                                  cu,
                                                  Andreas a/k/a MudGuard

                                                2. Hi Rolf,

                                                  ich habe nochmal versucht, feinzujustieren:

                                                  ### Zeilenanfang -> AB -> 0-n Großbuchstaben -> 1-n Ziffern -> 0-n Großbuchstaben oder Minusse -> Leerzeichen-Komma-Kombis
                                                  ^(?<startwort>AB[A-Z]*[\d]+[A-Z-]*)(?>\s*,\s*|\s+)
                                                  ### Ähnliches für die Gruppe startplus
                                                  (?<startplus>(?>AB[A-Z]*[\d]+[A-Z-]*(?>\s*,\s*|\s+))*)
                                                  ### unverändert
                                                  (?<vorwort>.*)\s+
                                                  ### unverändert
                                                  (?<zahl>\d+)\s+
                                                  ### Wort darf nun auch kleine Umlaute enthalten
                                                  (?<wort>[a-zA-Z0-9_üöä]+)\s+
                                                  ### unverändert
                                                  (?<betrag>[\d.,]+)\s*$
                                                  

                                                  Pit

                                                  1. Hi Rolf,

                                                    ich habe nochmal versucht, feinzujustieren:

                                                    Ich habe jetzt auch mal die komplette Datei durchlaufen lassen und anschließend das ergebnis kontrolliert und ich habe keinen fehler mehr gefunden.

                                                    Wenn also die Feinjustiererei nicht zu beanstanden ist, bedanke ich mich nochmal bei allen, die mit hier geholfen haben, besonders natürlich bei Rolf. Aber auch bei allen anderen, denn ich habe auch Vieles aus den anderen Beiträge gelernt, ob es bei ursus und Gunnar (sehr interessante Dinge) oder bei aus anderen Beiträgen wie dem von dedlfix, pl oder anderen Helfern war. Für mich jedenfalls eine sehr interessante und lehrreiche Geschichte.

                                                    Pit

                        2. Hallo Rolf,

                          ich sehe das nicht so negativ wie Jörg (ursus fastixiabundo :) ).

                          Ich auch nicht. Soweit ich die Daten übersehen kann, ist da nicht wirklich etwas komplett Unerwartetes dabei.

                          Wenn Du die einleitenden Codes separat haben willst, kannst Du das so machen:

                          /^(?<startwort>AB[\w\d]+)\s+(?<startplus>(AB[\w\d]+\s+)+)(?<vorwort>.*)\s+(?<zahl>\d+)\s+(?<wort>\w+)\s+(?<betrag>[\d.,]+)\s*$/
                          

                          Für mich ist bei solchen Aufgaben die Seite regex101.com sehr hilfreich. Da bekommst Du erklärt, was die Regex tut, und kannst sie ausprobieren.

                          Erstmal vielen Dank für die Hilfe. Die Regex ist echt der helle Wahnsinn.

                          Leider matcht sie im Moment noch nicht. Edit: Oops...sorry, natürlich matcht sie. ich bin auf meinen eigenen fehler im datensatz gestolpert 😂

                          Vielen herzlichen Dank für die Super-Regex!!!

                          Die Seite habe ich gestern kennen gelernt, ich wußte aber nicht, ob sie wat taugt oder nicht.

                          Pit

                        3. Hi Rolf nochmal,

                          hätte diese Zeile hier nicht auch matchen sollen?

                          Pit

                          1. ... habe das eingebaut und nun matcht sie:

                            ^(?<startwort>AB[\w\d]+)\s+(?<startplus>(AB[\w\d]+\s+)*)(?<vorwort>.*)\s+(?<zahl>\d+)\s+(?<wort>\w+)\s+(?<betrag>[\d.,]+)\s*$

                            Pit

                            1. Hallo Pit,

                              ich habe Dir zwei `Backticks` spendiert, damit das Sternchen nicht zur Kursivdarstellung führt.

                              Ja, sorry, da ist natürlich 0-n bei startplus notwendig.

                              Rolf

                              --
                              sumpsi - posui - clusi
                              1. Hallo Rolf,

                                ich habe Dir zwei `Backticks` spendiert, damit das Sternchen nicht zur Kursivdarstellung führt.

                                Ah, ok.

                                Ja, sorry, da ist natürlich 0-n bei startplus notwendig.

                                Kein Problem, so hatte ich wenigstens auch noch eine kleine Denksportaufgabe hieran zu lösen 😉

                                Ich bin eh immer noch hin- und weg ob Deiner Lösung!

                                Pit

                  3. Ausdrucks, der mit AB anfängt und dann ein weiteres Zeichen (Buchstabe oder Ziffer) hat und anschließend eine oder beliebig viele Ziffern bis zu einem Leerzeichen enthält.

                    Aha. Das ist schon sehr viel genauer als mir bisher bekannt war:

                    <?php
                    
                    $pattern[] = '^.*AB[A-Z0-9][0-9]+ (.*) ([0-9]+) ([0-9]+) (.*) ([0-9.,]*)$';
                    $pattern[] = '^.*AB[A-Z0-9][0-9]+ (.*) ([0-9]+) (.*) ([0-9.,]*)$';
                    $pattern   = '/' . implode('|', $pattern ) . '/';
                    
                    $rows = file('/tmp/data.txt');
                    foreach ( $rows as $row ) {
                    	$row = trim( $row );
                    	
                    	preg_match( $pattern, $row, $arr );
                    	
                    	$arrE=[];
                    	foreach($arr as $item) {
                    			if ( $item ) { $arrE[] = $item; }
                    	}
                    	
                    	if ( 5 == count( $arrE ) )  {
                    		$arrE[5] = $arrE[4];
                    		$arrE[4] = $arrE[3];
                    		$arrE[3] = $arrE[2];
                    		$arrE[2] = false;
                    	}
                    	
                    	print_r( $arrE );
                    }
                    

                    Ausgabe nach Test mit Deinen Daten:

                    Array
                    (
                        [0] => AB0006777 Lore Ipsum 25 ABC 3,72
                        [1] => Lore Ipsum
                        [2] => 
                        [3] => 25
                        [4] => ABC
                        [5] => 3,72
                    )
                    Array
                    (
                        [0] => AB09899 AB00067127 At vero, eos et 2 1 XYZ 13,11
                        [1] => At vero, eos et
                        [2] => 2
                        [3] => 1
                        [4] => XYZ
                        [5] => 13,11
                    )
                    Array
                    (
                        [0] => AB0007711 CD0TZUUZ AB899979 At vero eos et 10 100 XYZ 1.223,50
                        [1] => At vero eos et
                        [2] => 10
                        [3] => 100
                        [4] => XYZ
                        [5] => 1.223,50
                    )
                    
                    1. Hallo ursus contionabundo,

                      Array ( [0] => AB0007711 CD0TZUUZ AB899979 At vero eos et 10 100 XYZ 1.223,50 [1] => At vero eos et [2] => 10 [3] => 100 [4] => XYZ [5] => 1.223,50 )

                      Erstmal danke für Deine Lösung. Aber sie ist nicht ganz korrekt, denn z.b hier müßte der String At vero eos et auch die Zahl 10 enthalten, weil sie zum String gehört. Was mir sehr gefällt, ist der "aufgeräumte Code" in Deiner Lösung. Da kann ich einige Teile von übernehmen.

                      Pit

                      1. denn z.b hier müßte der String At vero eos et auch die Zahl 10 enthalten, weil sie zum String gehört.

                        Das macht es sogar einfacher:

                        <?php
                        $pattern = '/^.*AB[A-Z0-9][0-9]+ (.*) ([0-9]+) (.*) ([0-9.,]*)$/';
                        
                        $rows = file( '/tmp/data.txt' );
                        foreach ( $rows as $row ) {
                        
                        	$row = trim( $row );
                        	preg_match( $pattern, $row, $arr );
                        
                        	if ( $arr ) {
                        		print_r( $arr );
                        	} else {
                        		echo "Nicht passend: $row" . PHP_EOL;
                        	}
                        }
                        
                        1. Hi ursus,

                          aber es matcht bei mir nicht:

                          <?php
                          $pattern = '/^.*AB[A-Z0-9][0-9]+ (.*) ([0-9]+) (.*) ([0-9.,]*)$/';
                          
                          $rows = file('test1.txt');
                          foreach ( $rows as $row ) {
                          
                          	$row = trim( $row );
                          	preg_match( $pattern, $row, $arr );
                          
                          	if ( $arr ) {
                          		print_r( $arr );
                          	} else {
                          		echo "Nicht passend: $row" . PHP_EOL;
                          	}
                          }
                          
                          echo "Scriptende";
                          

                          text1.txt:

                          AB0006777 Lore Ipsum 25 ABC 3,72
                          AB09899 AB00067127 At vero eos et 2 25 XYZ 13,11
                          AB0007711 CD0TZUUZ AB899979 At vero eos et 10 25 XYZ 1.223,50
                          

                          Ausgabe:

                          Scriptende
                          

                          Gruß, Pit

                          1. Vermutlich ein Problem beim Einlesen der Datendatei.

                            Grund:

                            Würde nichts "matchen", dann gäbe es für jede Zeile die Ausgabe:

                            Nicht passend: [Zeile]
                            

                            Ob es funktioniert hat kannst Du mit

                            
                            $filename = 'test1.txt'
                            
                            if ( ! $rows = file( $filename ) ) {
                                echo "Fatal: '$filename' konnte nicht gelesen werden.";
                                trigger_error( "'$filename' konnte nicht gelesen werden.", E_USER_ERROR );
                            }
                            

                            statt:

                            $rows = file('test1.txt');
                            

                            feststellen.

                            Willst Du genaueres wissen, dann prüfe vorher wie folgt:

                            
                            error_reporting(E_ALL);
                            ini_set("display_errors", 1);
                            
                            if ( ! is_file( $filename ) ) {
                              trigger_error( "Fatal: '$filename' ist nicht vorhanden!", E_USER_ERROR );
                            } elseif ( ! is_readable( $filename ) ) {
                              trigger_error( "Fatal: '$filename' ist nicht lesbar!", E_USER_ERROR );
                            }
                            
                            1. Hallo Ursus,

                              Vermutlich ein Problem beim Einlesen der Datendatei.

                              Natürlich, Du hast Recht. Die Datei heißt nicht test1, sondern text1 😟

                              Grund:

                              Würde nichts "matchen", dann gäbe es für jede Zeile die Ausgabe:

                              Nicht passend: [Zeile]
                              

                              Da hätte ich auch selber drauf kommen können... 😀

                              
                              $filename = 'test1.txt'
                              
                              if ( ! $rows = file( $filename ) ) {
                                  echo "Fatal: '$filename' konnte nicht gelesen werden.";
                                  trigger_error( "'$filename' konnte nicht gelesen werden.", E_USER_ERROR );
                              }
                              

                              Werde ich ab sofort bei jedem Einlesen von Dateien verwenden! Danke.

                              error_reporting(E_ALL); ini_set("display_errors", 1);

                              if ( ! is_file( $filename ) ) { trigger_error( "Fatal: '$filename' ist nicht vorhanden!", E_USER_ERROR ); } elseif ( ! is_readable( $filename ) ) { trigger_error( "Fatal: '$filename' ist nicht lesbar!", E_USER_ERROR ); }

                              
                              

                              Noch besser ! 😀

                              Pit

                              1. Die Datei heißt nicht test1, sondern text1 😟

                                Seit dem mir GENAU DAS(sic! sic! sic!) passiert ist prüfe ich (jedenfalls außerhalb der schnellen Skripte im Terminal) stets, ob das Öffnen geklappt hat...

                                1. Die Datei heißt nicht test1, sondern text1 😟

                                  Seit dem mir GENAU DAS(sic! sic! sic!) passiert ist prüfe ich (jedenfalls außerhalb der schnellen Skripte im Terminal) stets, ob das Öffnen geklappt hat...

                                  ... und genau das mache ich ab sofort ebenfalls 😉

                                  Pit

                  4. @@Pit

                    … daher würde ich das Pferd gerne von hinten aufzäumen.

                    Dann mach das doch.

                    • Der Betrag steht immer am Ende der Zeile.

                    Das ist dann also irgendwas in Klammern ()$

                    Betrag hört mit zwei Ziffern auf, davor ein Komma: (,\d{2})$

                    Vor dem Komma eins bis drei Ziffern: (\d{1,3},\d{2})$

                    Davor können weitere Ziffern stehen, abgetrennt durch Punkt als Tausendertrennzeichen: ((?:\d{1,3}\.)*\d{1,3},\d{2})$

                    (?:…) gruppiert, ohne dass sich das Eingeklammerte gemerkt wird. Von diesen Gruppen kann es belibig viele (auch keine) geben: (?:…)*. Der Backslash in \. maskiert den Punkt, der ja in RegExp ein Sonderzeichen ist.

                    Stimmt aber so nicht, da zwischen Punkten bzw. zwischen Punkt und Komma immer genau drei Ziffern stehen müssen. Also die Gruppe verschoben: (\d{1,3}(?:\.\d{3})*,\d{2})$

                    • Mein ABC oder XYZ Wort steht immer durch Leerzeichen getrennt vor dem Betrag.

                    Genau ein Leerzeichen? ⁠ (\d{1,3}(?:\.\d{3})*,\d{2})$

                    Darf’s auch ein bisschen mehr sein? ⁠ +(\d{1,3}(?:\.\d{3})*,\d{2})$

                    • Die Zahl, die ich auch benötige, steht immer durch Leerzeichen getrennt vor dem ABC-/XYZ-Wort

                    Die feststehenden Wörter als Optionen: (ABC|XYZ) +(\d{1,3}(?:\.\d{3})*,\d{2})$

                    Leerzeichen davor: ⁠ +(ABC|XYZ) +(\d{1,3}(?:\.\d{3})*,\d{2})$

                    Ganzzahl davor, d.h. beliebig viele, mindestens eine Ziffer: (\d+) +(ABC|XYZ) +(\d{1,3}(?:\.\d{3})*,\d{2})$

                    • Alles was dann noch durch Leerzeichen getrennt links vor dem ABC-/XYZ-Wort steht brauche ich genau bis zum letzten Vorkommen plus Stringlänge eines Ausdrucks, der mit AB anfängt und dann ein weiteres Zeichen (Buchstabe oder Ziffer) hat und anschließend eine oder beliebig viele Ziffern bis zu einem Leerzeichen enthält.

                    Davor also noch ein String aus beliebigen Zeichen: (.*) +(\d+) +(ABC|XYZ) +(\d{1,3}(?:\.\d{3})*,\d{2})$

                    Dieses AB-Dingens willst du aber nicht haben: AB.\d* +(.*) +(\d+) +(ABC|XYZ) +(\d{1,3}(?:\.\d{3})*,\d{2})$

                    Vor dem AB-Dingens kann aber noch was stehen: (?:.* +)*AB.\d* +(.*) +(\d+) +(ABC|XYZ) +(\d{1,3}(?:\.\d{3})*,\d{2})$

                    Diesen Ausdruck in meinem Texteditor auf

                    AB0006777 Lore Ipsum 25 ABC 3,72
                    
                    AB09899 AB00067127 At vero, eos et 2 1 XYZ 13,11
                    
                    AB0007711 CD0TZUUZ AB899979 At vero eos et 10 100 XYZ 1.223,50
                    

                    losgelassen und durch $1;$2;$3;$4 (die geklammerten gemerkten Teile durch Semikolons getrennt) ersetzt ergibt:

                    Lore Ipsum;25;ABC;3,72
                    
                    At vero, eos et 2;1;XYZ;13,11
                    
                    At vero eos et 10;100;XYZ;1.223,50
                    

                    LLAP 🖖

                    --
                    „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
                    1. @@Pit

                      … daher würde ich das Pferd gerne von hinten aufzäumen.

                      Dann mach das doch.

                      […]

                      losgelassen und durch $1;$2;$3;$4 (die geklammerten gemerkten Teile durch Semikolons getrennt) ersetzt ergibt:

                      Lore Ipsum;25;ABC;3,72
                      
                      At vero, eos et 2;1;XYZ;13,11
                      
                      At vero eos et 10;100;XYZ;1.223,50
                      

                      Hi Gunnar,

                      boah, was für eine super Erklärung! Danke!

                      Beim Versuch, sie nachzuvollziehen (was mir, glaube ich, auch gelang) ist mir noch etwas aufgefallen: Sie gilt, so wie sie dort steht, für Beträge < 1 Mio., oder?

                      Pit

                      1. @@Pit

                        Sie gilt, so wie sie dort steht, für Beträge < 1 Mio., oder?

                        Nö, der * in (\d{1,3}(?:\.\d{3})*,\d{2}) sollte dafür sorgen, dass beliebig viele (auch keine) Dreiergruppen mit Punkt davor vorkommen dürfen.

                        LLAP 🖖

                        --
                        „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
              2. Na, dann wollen wir mal:

                data.txt:

                AB0006777 Lore Ipsum 25 ABC 3,72
                AB09899 AB00067127 At vero, eos et 2 1 XYZ 13,11
                AB0007711 CD0TZUUZ AB899979 At vero eos et 10 100 XYZ 1.223,50
                

                Ich will Dir nicht verschweigen, dass da jemand ganz schlecht geplant hat. Derartige divergierende Strings werden "teuer". Damit meine ich nicht nur die Rechenleistung (wegen der zu kombinierenden Patterns), sondern auch wegen der extremen Fehleranfälligkeit!

                Das scheinbar positive aber nur für Deine Beispieldaten gültige Ergebnis kann hier auf Grund von zahlreichen Unwägbarkeiten in den Daten nicht garantiert werden. Betrachte den Code also als kaputt und Deine Frage

                Kann man das überhaupt über eine einzige Regex ermitteln?

                als mit "NEIN" beantwortet. Das Problem muss an anderer Stelle gelöst werden.

                test.php:

                <?php
                
                $pattern[] = '^[A-Z0-9]{6,10} [A-Z0-9]{6,10} [A-Z0-9]{6,10} (.*) ([0-9]+) ([0-9]+) (.*) ([0-9.,]*)$';
                $pattern[] = '^[A-Z0-9]{6,10} [A-Z0-9]{6,10} (.*) ([0-9]+) ([0-9]+) (.*) ([0-9.,]*)$';
                $pattern[] = '^[A-Z0-9]{6,10} (.*) ([0-9]+) ([0-9]+) (.*) ([0-9.,]*)$';
                
                
                $pattern[] = '^[A-Z0-9]{6,10} [A-Z0-9]{6,10} [A-Z0-9]{6,10} (.*) ([0-9]+) (.*) ([0-9.,]*)$';
                $pattern[] = '^[A-Z0-9]{6,10} [A-Z0-9]{6,10} (.*) ([0-9]+) (.*) ([0-9.,]*)$';
                $pattern[] = '^[A-Z0-9]{6,10} (.*) ([0-9]+) (.*) ([0-9.,]*)$';
                
                
                $pattern = '/' . implode('|', $pattern ) . '/';
                
                $rows = file('/tmp/data.txt');
                foreach ( $rows as $row ) {
                	$row = trim( $row );
                	
                	preg_match( $pattern, $row, $arr );
                	
                	$arrE=[];
                	foreach($arr as $item) {
                			if ( $item ) { $arrE[] = $item; }
                	}
                
                	if ( 5 == count( $arrE ) )  {
                		$arrE[5] = $arrE[4];
                		$arrE[4] = $arrE[3];
                		$arrE[3] = $arrE[2];
                		$arrE[2] = false;
                	}
                	
                	print_r( $arrE );
                }
                

                Das klappt aber NUR dann, wenn die CODES genau 1 bis 3 mal vorkommen, stets eine Länge von 6 bis 10 Zeichen der Klasse [0-9A-Z] haben. Und wenn nichts dergleichen in dem gesuchten Text (genauer an dessen Anfang) vorkommt. Auch die Zifferngruppen vor dem gesuchten Text müssen genau 1 oder 2 mal vorkommen und der gesuchte Text darf nicht nur aus Ziffern bestehen oder mit einem Leerzeichen gefolgt von Ziffern " [0-9]+" enden.

                Array
                (
                    [0] => AB0006777 Lore Ipsum 25 ABC 3,72
                    [1] => Lore Ipsum
                    [2] => 
                    [3] => 25
                    [4] => ABC
                    [5] => 3,72
                )
                Array
                (
                    [0] => AB09899 AB00067127 At vero, eos et 2 1 XYZ 13,11
                    [1] => At vero, eos et
                    [2] => 2
                    [3] => 1
                    [4] => XYZ
                    [5] => 13,11
                )
                Array
                (
                    [0] => AB0007711 CD0TZUUZ AB899979 At vero eos et 10 100 XYZ 1.223,50
                    [1] => At vero eos et
                    [2] => 10
                    [3] => 100
                    [4] => XYZ
                    [5] => 1.223,50
                )
                
                
              3. Hintergrund ist, aus einem unsortierten Datenhaufen eine sortierte Tabelle oder csv zu machen.

                Dann reicht es ja, das Sortierkriterium zu isolieren. Was natürlich in jeder Zeile möglich sein muss. MfG

          2. Hallo Pit,

            Du schriebst:

            Ich benötige sowohl den String selber als auch die Zahl als auch den Betrag.

            Das heißt, du willst mithilfe eines regulären Ausdrucks einen Teil einer Zeichenkette ermitteln. Da ist es schon wichtig, welche Programmiersprache verwendet wird.

            Und falls mit „Betrag“ der mathematische Betrag gemeint ist, wäre die Programmiersprache auch wichtig.

            Ich habe das „benötigen“ schon als Problembeschreibung gesehen und weder frech noch fordernd.

            Bis demnächst
            Matthias

            --
            Pantoffeltierchen haben keine Hobbys.
            1. Hallo Matthias,

              Das heißt, du willst mithilfe eines regulären Ausdrucks einen Teil einer Zeichenkette ermitteln. Da ist es schon wichtig, welche Programmiersprache verwendet wird.

              Ah, ok. Und ja, genau darum geht es.

              Und falls mit „Betrag“ der mathematische Betrag gemeint ist, wäre die Programmiersprache auch wichtig.

              Ja, es ist der math. Betrag gemeint. Ich antworte im Naschgang auf diese Antwort auch noch ursus contionabundo, da werde ich dann mal 3 Beispieldatensätze posten. Dann wird es sicher noch klarer.

              Ich habe das „benötigen“ schon als Problembeschreibung gesehen und weder frech noch fordernd.

              Prima, denn das war meine Sorge und ich wollte tatsächlich nur das Problem sehr sachlich nüchtern beschreiben. Überhaupt...eigentlich würde ich das Problem gar nicht lösen müssen, aber ich habe mich da ein bischen hinein "verrant" und es läßt mir keine Ruhe, diese unstrukturierten Daten zu strukturieren. Aber selbstverständlich höflich, wenn ich hier schon um Mithilfe bitte. 😀

              Pit

          3. hallo

            Und meine Frage bezieht sich doch erstmal "nur" darauf, zu ermitteln, ob ich bei meiner Problemstellung mit einer Regex auf dem richtigen Weg bin oder ob ich mehrere Ausdrücke, ggf. gar im Zusammenspiel mit einer Programmier-/Scriptsprache brauche.

            Wenn man RegEx vermeiden kann, sollte man das tun. Das ist immer dann der Fall, wenn man selber Zugang zu den Rohdaten hat.

            Eine Regex kann nur so zuverlässig arbeiten, wie auch der Agorithmus, der den String erzeugt, eindeutig definiert ist. In allen anderen Fällen wird das Ergebnis dieser Massnahme unzuverlässig.

            Z.B. kann man mit einer einzigen Regex Email-Adressen zerlegen. Nur würde ich mir das Pattern dazu nur dann selber schreiben, wenn ich den Standard (RFC 5322, RFC 5321) für Email-Adressen auch akribisch umsetze.

            1. Hallo,

              Wenn man RegEx vermeiden kann, sollte man das tun. Das ist immer dann der Fall, wenn man selber Zugang zu den Rohdaten hat.

              Habe ich. Aber was nützt das, wenn es unsortierter "Datenkram" ist, den man strukturiert benötigen würde?

              Eine Regex kann nur so zuverlässig arbeiten, wie auch der Agorithmus, der den String erzeugt, eindeutig definiert ist. In allen anderen Fällen wird das Ergebnis dieser Massnahme unzuverlässig.

              Absolut!

              Pit

      2. Die Programmiersprache wird in dem Moment interessant wenn es darum geht, das Ergebnis zu erhalten. Also wenn das Ergebnis mehr ist als nur 1 oder 0, z.B. eine bestimmte Datenstruktur. Einfaches Beispiel für ein Array:

        my $s = " 25 EUR ";
        my $p = [ $s =~ /(\d+) +([a-zA-Z]+)/ ];
        printf qq(Betrag: %d, Währung %s), abs($p->[0]), $p->[1];
        

        Oder ein Hash (assoziatives Array):

        my $s = "foo=bar;dog=boo";
        my $r = { $s =~ /(\w+)=(\w+)/g };
        print Dumper $r;
        
        $VAR1 = {
                  'dog' => 'boo',
                  'foo' => 'bar'
                };
        

        MfG

        1. Die Programmiersprache wird in dem Moment interessant wenn es darum geht, das Ergebnis zu erhalten. Also wenn das Ergebnis mehr ist als nur 1 oder 0, z.B. eine bestimmte Datenstruktur. Einfaches Beispiel für ein Array:

          my $s = " 25 EUR ";
          my $p = [ $s =~ /(\d+) +([a-zA-Z]+)/ ];
          printf qq(Betrag: %d, Währung %s), abs($p->[0]), $p->[1];
          

          Oder ein Hash (assoziatives Array):

          my $s = "foo=bar;dog=boo";
          my $r = { $s =~ /(\w+)=(\w+)/g };
          print Dumper $r;
          
          $VAR1 = {
                    'dog' => 'boo',
                    'foo' => 'bar'
                  };
          

          Hi pl,

          danke für das Beispiel.

          Ich beschäftige mich alle Jubeljahre wieder mal mit Regexen und finde sie jedesmal aufs Neue wieder kryptisch, aber auch faszinierend 😀

          Pit

          1. Ich beschäftige mich alle Jubeljahre wieder mal mit Regexen und finde sie jedesmal aufs Neue wieder kryptisch, aber auch faszinierend 😀

            Ich beschäftige mich seit vielen Jahren regelmäßig mit Regexen und kann mich noch gut an die anfängliche Begeisterung erinnern. Das hat sich mit der Zeit geändert.

            Zitat: Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems.

          2. RegEx'n finde ich, sind von allen anderen Möglichkeiten die es gibt, die unzweckmäßigste und auch am meisten störanfälligste Art, aus Texten Datenstrukuren zu erzeugen. MfG

            1. Hallo pl,

              ich pack aber nicht immer gleich den Antlr aus wenn ich was parsen will :)

              Und das manuelle Ausprogrammieren eines Parsers für den Typ von Zeilen, die Pit da hat, macht auch keinen Spaß.

              Da finde ich den Programmosaurus Regex doch schon ganz nett. Ich gebe Zeilen hinein, bekomme die Fragmente heraus, das ist effektiv. Es ist möglicherweise nicht effizient, wenn man größere Mengen an Zeilen zu durchwühlen hat. Aber die Zweckmäßigkeit absprechen würde ich dem Tierlein deswegen noch nicht.

              Störanfällig ist es auch nicht, aber wenn man nicht exakt weiß, wie man mit ihm umgehen muss, kann es beißen. Wohin das führt, haben wir in Jurassic Park alle gesehen. Und Fehler im Umgang fallen bei diesem Reptil leicht, insofern hast Du recht.

              Rolf

              --
              sumpsi - posui - clusi
              1. Hi Rolf,

                Serialize Algorithmen sind nur dann zweckmäßig wenn sie umkehrbar sind. Genau das ist der Knackpunkt: RegEx'n sind nicht umkehrbar.

                MfG

                1. Hallo pl,

                  meep mip mip beeeeeep FAILURE TO COMPREHEND

                  Was hat Pits Problem mit Serialisierung und Umkehrbarkeit zu tun?

                  Rolf

                  --
                  sumpsi - posui - clusi
                  1. Was hat Pits Problem mit Serialisierung und Umkehrbarkeit zu tun?

                    Was hat Programmierung mit Faszination zu tun? \s+ ist nicht umkehrbar! MfG

            2. @@pl

              RegEx'n finde ich, sind von allen anderen Möglichkeiten die es gibt, die unzweckmäßigste und auch am meisten störanfälligste Art, aus Texten Datenstrukuren zu erzeugen.

              Wenn die Daten so vorliegen, dass sie mit RexExp in die gewünschte Form gebracht werden können, sind RexExp eine sehr zweckmäßige Art, das zu tun. Dazu braucht man nicht einmal ein Script (PHP oder was auch immer); das kann jeder vernünftige Tetxeditor.

              LLAP 🖖

              --
              „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
      3. Tach!

        Ich benötige sowohl den String selber als auch die Zahl als auch den Betrag.

        Kein Problem. In welcher Programmiersprache?

        In php. Aber ist das für die (ggf.) Regex denn wichtig?

        Die Syntax der verwendeten RegExp-Bibliotheken ist je nach Sprache und Version unterschiedlich. Viele Dinge sind alt und deshalb überall gleich, aber einige Dinge sind proprietär, und deshalb nicht überall (gleichermaßen) verwendbar.

        dedlfix.

        1. Die Syntax der verwendeten RegExp-Bibliotheken ist je nach Sprache und Version unterschiedlich. Viele Dinge sind alt und deshalb überall gleich, aber einige Dinge sind proprietär, und deshalb nicht überall (gleichermaßen) verwendbar.

          Hi dedlfix,

          gut zu wissen, danke.

          Pit