Reputation: 1381
This is a simple problem but I'm wasting too much time trying to figure it out on my own.
I had data stored in strings with the pattern r{N}-{N}s{N}
where {N} is a one or two digit number. This pattern can repeat up to 5 times. I need to extract the numbers from the pattern, preferably grouped somehow.
For example, if the string were "r4-10s5"
, I want to extract {4,10,5}
If the string were "r4-10s5r6-7s8"
I want to extract {4,10,5} {6,7,8}
How could I get this done in PHP?
I have tried using recursive regular expressions but I cannot get them to match properly.
Upvotes: 0
Views: 80
Reputation: 13283
This is how I would do it:
function extractNumbers($string, $multiples = 3, $strict = false) {
$string = preg_replace('/\D+/', ' ', trim($string));
$array = explode(' ', trim($string));
$count = count($array);
$remove = ($count % $multiples);
if ($remove > 0) {
// Strict, do not allow dangling numbers
if ($strict) {
return null;
}
$array = array_slice($array, 0, ($count - $remove));
}
$array = array_map('intval', $array);
return array_chunk($array, $multiples);
}
$str = 'r4-10s5r6-7s8';
var_dump(extractNumbers($str));
It may not be very elegant, but it is relatively easy to understand and maintain.
Upvotes: -1
Reputation: 5896
$str = "r4-10s5r6-7s8";
preg_match_all("#r(\d{1,2})-(\d{1,2})s(\d{1,2})#", $str, $matches);
// group the matches together
$sets = array();
for ($i = 0, $count = count($matches[0]); $i < $count; $i++)
$sets[] = array($matches[1][$i], $matches[2][$i], $matches[3][$i]);
print_r($sets);
Outputs:
array (size=2)
0 =>
array (size=3)
0 => string '4' (length=1)
1 => string '10' (length=2)
2 => string '5' (length=1)
1 =>
array (size=3)
0 => string '6' (length=1)
1 => string '7' (length=1)
2 => string '8' (length=1)
Another option that doesn't have the loop would be:
preg_match_all("#r(\d{1,2})-(\d{1,2})s(\d{1,2})#", $str, $matches, PREG_SET_ORDER);
print_r($matches);
Outputs:
array (size=2)
0 =>
array (size=4)
0 => string 'r4-10s5' (length=7)
1 => string '4' (length=1)
2 => string '10' (length=2)
3 => string '5' (length=1)
1 =>
array (size=4)
0 => string 'r6-7s8' (length=6)
1 => string '6' (length=1)
2 => string '7' (length=1)
3 => string '8' (length=1)
Upvotes: 1
Reputation: 10169
The static pattern is: r-
s
and the empty spots can be only numbers
/r(\d{1,2})-(\d{1,2})s(\d{1,2})/
=> test here: http://regex101.com/r/sH4sY0
\d{1,2}
matches 1 or 2 digits in a row
Upvotes: 1