Manu: preg_split

Hallo zusammen,

irgendwie bin ich heute etwas lahm... Ich muss einen String in der Art '0,5 ml' zerlegen, um, mit dem ersteren Wert eine Berechnung durchzuführen und dann die Maßeinheit wieder anzuhängen. Ich mache das momentan noch so:
list($fQuantity,$sQuantity) = explode(" ",$this->quantity);

Jetzt habe ich aber festgestellt, dass ich bei einem (und wahrscheinlich ist es nicht allein) Produkt kein Leerzeichen habe (das sieht so aus: '0,5ml'). Mein Versuch, das ganze mit preg_split zu zerhacken (bspw. list($fQuantity,$sQuantity) = preg_split("/[0-9]/",$this->quantity);), ist kläglich gescheitert - hier bekomme ich nur einen Wert heraus (und regex sind heute auch nicht mein Ding :(.
Dummerweise kann ich die DB-Daten (quantity) nicht eifach ändern, das sind einfach zu viele...

Welche Möglichkeiten bieten sich mir denn noch (bitte langsam schreiben, ich bin heute blond...)?

Gruß,
Manu

  1. Servus,

    mit preg_split wirst du nicht weit kommen, denn es ist schwierig, nach 'nichts' aufzuteilen.

    Verwende ein simples preg_match. Dies könnte vereinfacht so aussehen:

    %([0-9,.])[ ]*([a-z])%i

    Je nach mglicher Komplexität der Komponenten muss man das ganze evtl. noch etwas anpassen.

    Gruss
    Patrick

    --
    sh:( fo:| ch:? rl:( br:> n4:( ie:% mo:) va:} de:> zu:) fl:| ss:| ls:[ js:|
    1. Hallo Patrick,
      vielen Dank für die Antwort, der Tipp war sehr hilfreich... you made my day ;)

      ich habe das so umgebaut und finde damit sowohl '1000 Tests' und auch '1ml':

      preg_match('%([0-9,.]*)[ ]*([a-z]*)%i',$product->quantity,$aTreffer);

      Gruß,
      Manu

      1. Hi,

        gehts damit?
        preg_replace("#([0-9]+)((,|.)([0-9]+))?[^0-9]*#i", "\1.\4", $string)

        Gruesse, Joachim

        --
        Am Ende wird alles gut.
        1. Hello Joachim,

          gehts damit?
          preg_replace("#([0-9]+)((,|.)([0-9]+))?[^0-9]*#i", "\1.\4", $string)

          könntest Du das bitte etwas erläutern?
          Mit Regular Expressions tu ich mich auch immer noch schwer und nutze daher gerne die Gelegenheit, wenn ich mal eine "einfache" erklärt bekomme.

          #             Begrenzer für das Pattern
          ([0-9]+)      die Ziffernzeichen 1 bis n Mal, warum in Klammern?

          ((,|.)([0-9]+))?  Die Gruppe in Klammern 0 oder 1 Mal

          (,|.)     entweder Komma oder Punkt, Der Punkt muss escaped werdern
             ([0-9]+)   Ziffernzeichen 1 bis n Mal

          [^0-9]*       Alle Zeichen, die keine Ziffern sind 0 bis n Mal
                        Warum "keine Ziffern?" es dürfte da doch im Prinzip nichts anderes
                        als Whitespace stehen, oder?

          #             Ende des Pattern

          i             case Insensitive, wieso? sind doch keinen Lettern da?

          ", "\1.\4", $string)  und da verließen sie ihn. Backreferenzen? was bedeuten die?

          Harzliche Grüße vom Berg
          http://bergpost.annerschbarrich.de

          Tom

          --
          Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
          Nur selber lernen macht schlau
          Ein Jammer ist auch, dass die Dummen so selbstsicher und die Klugen voller Zweifel sind. Das sollte uns häufiger zweifeln lassen :-)

          1. Servus,

            ([0-9]+)      die Ziffernzeichen 1 bis n Mal, warum in Klammern?

            Weil dieser Teil des Ausdrucks weiterverarbeitet werden soll (s.u.)

            [^0-9]*       Alle Zeichen, die keine Ziffern sind 0 bis n Mal
                          Warum "keine Ziffern?" es dürfte da doch im Prinzip nichts anderes als Whitespace stehen, oder?

            Doch, da darf die Einheit stehen, mit oder ohne Leerzeichen davor.

            i             case Insensitive, wieso? sind doch keinen Lettern da?

            Ja, das spielt hier keine Rolle, aber es schadet auch nicht ;)

            ", "\1.\4", $string)  und da verließen sie ihn. Backreferenzen? was bedeuten die?

            Backreferenzen sind die gefundenen Teilausdrücke die in Klammern gepackt sind. Um auf die Zahl zu kommen, muss man einfach die Klammern durchzählen:

            ([0-9]+)((,|.)([0-9]+))?
            ^------^                    \1
                    ^--------------^    \2
                     ^----^             \3
                           ^------^     \4

            Wir wollen nur \1 (die Vorkomma-Stellen) und \4 (die Nachkomma-Stellen). \3 (das Komma) und \4 (Komma + Nachkomma-Stellen) interessieren uns nicht, genausowenig wie alles was danach kommt (Einheit), weil wir selbige nicht zum Rechnen brauchen.

            "\1.\4"

            \1 Damit haben wir Vorkommastellen,
            .  einen einheitlichen Punkt als Komma
            \4 sowie die Nachkommastellen

            Dieser String lässt sich nun problemlos in einen Float umwandeln zum rechnen.

            Wenn wir nun schon so weit sind, können wir gleich noch weiter verbessern:

            preg_replace('#([\d]+)((,|.)([\d]+))?.*#', '\1.\4', $string);

            Double quotes hab ich durch single quotes ersetzt, dadurch braucht PHP den String nicht unnötig zu parsen und wir müssen im 'Replace'-Teil die Backreferenzen nicht doppelt escapen.
            Dann ersetzen wir noch die Menge der 'Nicht-Zeichen' mit allen Zeichen, damit Einheiten wie z.B. m2 (Quadratmeter) durchkommen (Wer weiss in welch lustigen Formaten die Daten vorliegen mögen ;). Sobald das erste nicht-numerische Zeichen gefunden wird haben wir unsere Zahl, die wir zum Rechnen brauchen, eh schon zusammen, da spielt es keine Rolle ob in der Einheit noch weitere Zahlen auftauchen.

            Gruss
            Patrick

            --
            sh:( fo:| ch:? rl:( br:> n4:( ie:% mo:) va:} de:> zu:) fl:| ss:| ls:[ js:|
            1. Hello,

              ...
              was aber trotzdem fehlt ist die Einheit, die Manu später mit der Zahl ausgeben will, also in Zusammenhang mit dieser, aber eben separiert, benötigt.

              Sicherlich wird die beendet durch ein Whitespace oder ein Satzzeichen, also eine Wortgrenze. Und sie wird vermutlich auch mindestens mit einem Buchstaben anfangen.

              Das wird mann dann aber mit preg_match machen müssen, oder?

              Harzliche Grüße vom Berg
              http://bergpost.annerschbarrich.de

              Tom

              --
              Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
              Nur selber lernen macht schlau
              Ein Jammer ist auch, dass die Dummen so selbstsicher und die Klugen voller Zweifel sind. Das sollte uns häufiger zweifeln lassen :-)

              1. Servus,

                was aber trotzdem fehlt ist die Einheit, die Manu später mit der Zahl ausgeben will

                in der Tat, jetzt weiss ich auch wieder warum ich beim ersten Mal preg_match genommen hab ;) In dem Fall einfach den letzten Teil auch Klammern und mit preg_match auslesen.

                Gruss
                Patrick

                --
                sh:( fo:| ch:? rl:( br:> n4:( ie:% mo:) va:} de:> zu:) fl:| ss:| ls:[ js:|
                1. Hallo zusammen,

                  ich habe jetzt erst die anderen Postings gesehen...nicht schlecht..wieder was gelernt. So laaangsam verlieren regex' den Dunst des Mystischen ;)

                  Ich denke, ich werde mir (wenn ich etwas Zeit habe) die zweite etwas genauer anschauen, sprich einbauen, da es sicher noch mehr Zeichen in der Einheit gibt, die betrachtet werden müssen (momentan greife ich mir [a-zµ], mir sind allerdings keine weiteren Maßeinheitenkürzel aufgefallen...)

                  Danke für die Hinweise & Gruß,
                  Manu

                  --
                  Deutschland ist einfach von einer Diktatur der Nationalsozialisten zu einer Diktatur der Gutmenschen übergegangen.
                2. Hello,

                  Fall einfach den letzten Teil auch Klammern und mit preg_match auslesen.

                  Ich hab noch damit herumprobiert, aber krieg das Gewünschte  nicht hin...

                  Es soll nur '13,4g' rauskommen

                  $string  = 'Für die Sauce nehmen wir 13,4g Käse vom alten Gouda';
                  $pattern = '#([\d]+)((,|.)([\d]+))?(\s*.+)?#';
                  $backref = '\1.\4 \5';

                  $ergebnis = preg_replace($pattern, $backref, $string);

                  Ausgabe:

                  string: Für die Sauce nehmen wir 13,4g Käse vom alten Gouda
                  pattern: #([\d]+)((,|.)([\d]+))?(\s*.+)?#
                  backref: \1.\4 \5
                  ergebnis:Für die Sauce nehmen wir 13.4 g Käse vom alten Gouda

                  Harzliche Grüße vom Berg
                  http://bergpost.annerschbarrich.de

                  Tom

                  --
                  Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                  Nur selber lernen macht schlau
                  Ein Jammer ist auch, dass die Dummen so selbstsicher und die Klugen voller Zweifel sind. Das sollte uns häufiger zweifeln lassen :-)

                  1. Hello,

                    so langsam tut's ja...
                    Warum die anderen Möglichkeiten aber alle nicht funktioniert haben, weiß ich noch nicht.

                    preg_replace():

                    string:  Aber nicht mehr als 1,3 Liter Milch reintun
                    pattern: #\D*([\d]+)((,|.)([\d]+))?(\s*(\S*))?.*#
                    backref: $1.$4 $6
                    Ergebnis:1.3 Liter

                    preg_match():

                    string:  Aber nicht mehr als 1,3 Liter Milch reintun
                    pattern: #\D*([\d]+)((,|.)([\d]+))?(\s*(\S*))?.*#
                    Ergebnis:1
                    Treffer: Array
                    (
                        [0] => Aber nicht mehr als 1,3 Liter Milch reintun
                        [1] => 1
                        [2] => ,3
                        [3] => ,
                        [4] => 3
                        [5] =>  Liter
                        [6] => Liter
                    )

                    Harzliche Grüße vom Berg
                    http://bergpost.annerschbarrich.de

                    Tom

                    --
                    Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                    Nur selber lernen macht schlau
                    Ein Jammer ist auch, dass die Dummen so selbstsicher und die Klugen voller Zweifel sind. Das sollte uns häufiger zweifeln lassen :-)

                    1. Hello,

                      mit:

                      $ergebnis = preg_match_all($pattern, $string, $_matches, PREG_PATTERN_ORDER || PREG_OFFSET_CAPTURE);

                      string:  Und höchstens 3 Mal umrühren in 7,5 Stunden, auch morgens
                      pattern: #([\d]+)((,|.)([\d]+))?(\s*(\S*))?#
                      Ergebnis:2
                      Treffer: Array
                      (
                          [0] => Array
                              (
                                  [0] => 3 Mal
                                  [1] => 7,5 Stunden,
                              )

                      [1] => Array
                              (
                                  [0] => 3
                                  [1] => 7
                              )

                      [2] => Array
                              (
                                  [0] =>
                                  [1] => ,5
                              )

                      [3] => Array
                              (
                                  [0] =>
                                  [1] => ,
                              )

                      [4] => Array
                              (
                                  [0] =>
                                  [1] => 5
                              )

                      [5] => Array
                              (
                                  [0] =>  Mal
                                  [1] =>  Stunden,
                              )

                      [6] => Array
                              (
                                  [0] => Mal
                                  [1] => Stunden,
                              )

                      )

                      Wie bekommt man nun das Komma (kann auch : . ! ? sein) hinter Stunden noch weg?

                      Harzliche Grüße vom Berg
                      http://bergpost.annerschbarrich.de

                      Tom

                      --
                      Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                      Nur selber lernen macht schlau
                      Ein Jammer ist auch, dass die Dummen so selbstsicher und die Klugen voller Zweifel sind. Das sollte uns häufiger zweifeln lassen :-)

                      1. Hello,

                        Wie bekommt man nun das Komma (kann auch : . ! ? sein) hinter Stunden noch weg?

                        Ok, jetzt nur nicht aufgeben! ;-)

                        Das Komma als Wortgrenze ist fort *jippie*

                        $string  = 'Und höchstens 3 Mal umrühren in 7,5 Stunden, auch morgens. Nur abends nach 20:00 Uhr nicht mehr';
                        $pattern = '#([\d]+)((,|.|:)([\d]+))?(\s*(\S*\b)?)?#';
                        $ergebnis = preg_match_all($pattern, $string, $_matches, PREG_PATTERN_ORDER || PREG_OFFSET_CAPTURE);

                        echo "string:  ".htmlspecialchars(print_r($string,1))."<br>";
                        echo "pattern: ".htmlspecialchars(print_r($pattern,1))."<br>";
                        echo "Ergebnis:".htmlspecialchars(print_r($ergebnis,1))."<br>";
                        echo "Treffer: ".htmlspecialchars(print_r($_matches,1))."<br>";

                        Wer wäre jetzt noch so nett, und optimiert das Pattern nochmal?

                        Harzliche Grüße vom Berg
                        http://bergpost.annerschbarrich.de

                        Tom

                        --
                        Fortschritt entsteht nur durch die Auseinandersetzung der Kreativen
                        Nur selber lernen macht schlau
                        Ein Jammer ist auch, dass die Dummen so selbstsicher und die Klugen voller Zweifel sind. Das sollte uns häufiger zweifeln lassen :-)