9

I would like to convert a string of delimited dimension values into floating numbers.

For example

152.15 x 12.34 x 11mm

into

152.15, 12.34 and 11

and store in an array such that:

$dim[0] = 152.15;
$dim[1] = 12.34;
$dim[2] = 11;

I would also need to handle scenarios where the delimiting text is different and the numbers may be followed by a unit expression like:

152.15x12.34x11 mm

152.15mmx12.34mm x 11mm
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
Tian Bo
  • 551
  • 3
  • 7
  • 12

6 Answers6

19
$str = '152.15 x 12.34 x 11mm';
preg_match_all('!\d+(?:\.\d+)?!', $str, $matches);
$floats = array_map('floatval', $matches[0]);
print_r($floats);

The (?:...) regular expression construction is what's called a non-capturing group. What that means is that chunk isn't separately returned in part of the $mathces array. This isn't strictly necessary in this case but is a useful construction to know.

Note: calling floatval() on the elements isn't strictly necessary either as PHP will generally juggle the types correctly if you try and use them in an arithmetic operation or similar. It doesn't hurt though, particularly for only being a one liner.

cletus
  • 616,129
  • 168
  • 910
  • 942
  • You can ditch the outer parentheses, and then $matches[0] will contain the matches. Also, what's the purpose of `?:` ? – troelskn Jun 03 '09 at 12:22
  • 1
    You're quite right about the outer parentheses. Changed that. ?: makes whats inside those parentheses as a non-capturing group, meaning it wont separately be put in the $matches array anywhere, which it would be if you didnt include it. Not strictly necessary but cleaner and in more complicated examples may be necessary. – cletus Jun 03 '09 at 12:24
  • @cletus: You're absolutely right about the non-capturing parenthesis, but it makes the regex way less readable imo. I "get" Paolo's regex much faster then yours. – soulmerge Jun 03 '09 at 12:43
  • Well, look on the bright side: you learnt something extra. :) Non-capturing groups are useful. – cletus Jun 03 '09 at 12:44
  • Also, I read mine and its clear that I'm not interested in separately capturing parts of the number, just the whole number. The above clearly matches your intent, which is what you should be striving for imho. – cletus Jun 03 '09 at 12:47
  • It might be useful to also cast $matches[0] results as (float) – Ambirex Jun 03 '09 at 15:29
  • Thanks for the explanation, cletus. For some reason, I didn't know about non-capturing groups. Now I do. – troelskn Jun 03 '09 at 17:57
4
<?php

$s = "152.15 x 12.34 x 11mm";

if (preg_match_all('/\d+(\.\d+)?/', $s, $matches)) {
    $dim = $matches[0];
}

print_r($dim);

?>

gives

Array
(
    [0] => 152.15
    [1] => 12.34
    [2] => 11
)
nonopolarity
  • 146,324
  • 131
  • 460
  • 740
2
$string = '152.15 x 12.34 x 11mm';
preg_match_all('/(\d+(\.\d+)?)/', $string, $matches);
print_r($matches[0]); // Array ( [0] => 152.15 [1] => 12.34 [2] => 11 ) 
Paolo Bergantino
  • 480,997
  • 81
  • 517
  • 436
1

Using sscanf() affords the same level of required flexibility as a preg_ function call, but sscanf() is better because it allows you to explicitly cast the targeted values as floats from its format parameter.

%f means a float number substring and %*[mx ] matches and silently ignores the unwanted separators.

Now there is no need to call floatval() within array_map() to cast the float values.

Code: (Demo)

var_dump(
    sscanf($test, '%f%*[mx ]%f%*[mx ]%f')
);

Output:

array(3) {
  [0]=>
  float(152.15)
  [1]=>
  float(12.34)
  [2]=>
  float(11)
}
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
1
$str = "152.15 x 12.34 x 11mm";
$str = str_replace("mm", "", $str);
$str = explode("x", $str);
print_r($str); // Array ( [0] => 152.15 [1] => 12.34 [2] => 11 ) 

Tested it and it works on all strings above.

Ólafur Waage
  • 68,817
  • 22
  • 142
  • 198
0
preg_match_all("/\d*\.?\d+|\d+/", "152.15mmx12.34mm x .11mm", $matches);

This example supports numbers like .11 as well, since they are valid numbers. $matches[0] will contain 152.15, 12.34 and 0.11, given that you type cast the result to float. If you don't 0.11 will appear as .11. I would type cast using array_map.

$values = array_map("floatval", $matches[0]); 

You can use the values for anything math without type casting them though. casting is just needed when printing them directly.

runfalk
  • 1,996
  • 1
  • 17
  • 20