You can use preg_replace_callback
to match the numbers in parenthesises, then use explode
and array_map
to turn it into integers, then sort it, and then check for range.
Function:
function fixRange($match) {
// Extract the numbers
$numbers = array_map('intval', explode(',', $match[1]));
// Make sure they're sequential
sort($numbers);
$count = count($numbers);
$replacements = [];
for ($i = 0; $i < $count; $i++) {
$startNumber = $endNumber = $numbers[$i];
for ($j = $i + 1; $j < $count; $j++) {
if ($numbers[$j] === ($endNumber + 1)) {
$endNumber = $numbers[$j];
$i = $j;
} else {
break;
}
}
// Add range if $endNumber is not the same as $startNumber
$replacements[] = $startNumber . ($startNumber !== $endNumber ? '-' . $endNumber : '');
}
return '(' . implode(',', $replacements) . ')';
}
Example:
<?php
$raw = "outside 1,2,12,13 (5,6,11,12,13,14,16,19,20,21)";
$result = preg_replace_callback('~\(([^\)]+)\)~', 'fixRange', $raw);
var_dump($result);
// string(38) "outside 1,2,12,13 (5-6,11-14,16,19-21)"
$raw = "outside 1,2,12,13 (5,6,11,12,13,14,16,19,20,21,22,23,25)";
$result = preg_replace_callback('~\(([^\)]+)\)~', 'fixRange', $raw);
var_dump($result);
// string(41) "outside 1,2,12,13 (5-6,11-14,16,19-23,25)"
DEMO