robertnovak robertnovak - 1 year ago 84
PHP Question

preg_match doesn't work like a test online

I have code to split weights and cubics number and unit.
for example 540ml to "540" and "ml" the number part of preg_match works fine, but the preg_match unit return in array is only "m".

When I test online this regex works fine too. But I don't know why php return in arrays only the first letter. I tried all regex for only letter but it doesn't work.

preg_match("/.[0-9]*/", $string, $number);<br/>
preg_match("/[(ml)(g)(kg)(l)]{1,1}[(ml)(g)(kg)(l)]{0,1}/", $string, $unit);

Answer Source

The reason why the second preg_match does not work as you expect is that the letters in square brackets are treated as atomic letters without any sense of sequence. The match is therefore with any one of them, but not in series.

So even though you put (ml) in the first square bracket part, it will match both "m" or "l", whichever is the current character, but not both. It will even match brackets, as they are treated as any other character inside square brackets.

So your total expression will therefore match both "kg" and "gk", but also ")g" and "m(". What you are really looking for is the pipe (|) operator which functions as an OR.

There is also a problem with the first regular expression as the first character can be anything (the meaning of .). You probably wanted to be sure to match at least one digit. For that you should use the + operator (instead of the *).

Also, you can perfectly match the two parts with one regular expression, by using capture groups denoted with brackets.

Taking all the above together, you get this:

$string = "123kg";

preg_match("/\b([0-9]+)(ml|g|kg|l)\b/", $string, $parts);

if (count($parts)) {
    echo "number: " . $parts[1] . "<br />" . 
        "unit: " . $parts[2] . "<br />";
} else {
    echo "no match";


number: 123

unit: kg