I want to translate/hydrate/expand/parse a comma-separated string of integers and hyhenated integer range expressions and populate an array with its equivalent values as individual integers elements.
Input strings might look like the following:
3,5,6,9,11,23
or
3-20
or
3-6,8,12,14-20
I want to return these as an array of integers, so the last one would become:
[3,4,5,6,8,12,14,15,16,17,18,19,20]
Is there either a function available that does this, or how would I start in writing one?
You are probably looking for the range
function and implode
:
$input = '3,5,6,9,11,23,14-77';
$result = preg_replace_callback('/(\d+)-(\d+)/', function($m) {
return implode(',', range($m[1], $m[2]));
}, $input);
gives you:
3,5,6,9,11,23,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77
Demo
How it works: You basically have two tokens in your string: the range-token (1-n)
(defined as regular expression: (\d+)-(\d+)
) and the fallback (anything else).
preg_replace_callback
allows the expansion of the token string by a callback function. That callback function then just expands the two matched numerical values into the comma-separated list by using PHP's range
function and implode
.
After that the string is in a normalized format you can just explode
it:
// as array:
print_r(explode(',', $result));
Full Demo
And after years as it was requested well formulated, the integer array, you can easily treat it as a JSON Array:
$result = json_decode('['. preg_replace_callback('/(\d+)-(\d+)/', function($m) {
return implode(',', range($m[1], $m[2]));
}, $input) .']');
var_dump($result);
Demo PHP 5.3-8.1 + Git Master
Here's a formalization/formulation of hakre's excellent answer:
function rangesToList($a, $max) {
$a = trim($a);
if (isset($max) && substr($a, -1) == "-") {
$a .= $max;
}
$r = preg_replace_callback('/(\d+)-(\d+)/', function($m) {
return implode(',', range($m[1], $m[2]));
}, $a);
return array_map('intval', explode(",", $r));
}
In addition to being encapsulated into a formula and a little more robust, it also takes an optional $max
argument so that you can give it input like this:
$in = "2,4,6-8, 12-";
$out = rangesToList($in, 14);
and get this
Array
(
[0] => 2
[1] => 4
[2] => 6
[3] => 7
[4] => 8
[5] => 12
[6] => 13
[7] => 14
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With