preg_split
Manu
- php
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
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
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
Hi,
gehts damit?
preg_replace("#([0-9]+)((,|.)([0-9]+))?[^0-9]*#i", "\1.\4", $string)
Gruesse, Joachim
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
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
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
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
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
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
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
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
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