1

I have a text box that a user can paste a string of comma separated numbers and it puts that into an array. However, in some cases that string may contain numbers separated by a dash and I need to fill in the missing numbers where that dash appears.

Example:

1, 4, 7, 20-25, 31, 46, 100

Needs to become:

1, 4, 7, 20, 21, 22, 23, 24, 25, 31, 46, 100

How might I go about doing this? The gap wont always be 5 numbers and there could be more than one set of dashed numbers in the string that is input.

nickb
  • 59,313
  • 13
  • 108
  • 143
Jason
  • 23
  • 5
  • 1
    Grab the input, explode on ",", strip the whitespace. From here you have an array of your numbers. Iterate through them and strpos for any dashes or just explode on "-". That'll give you the starting number and the ending number, fill in the gaps with a for loop. – Chris Rasco Sep 11 '13 at 19:03

5 Answers5

2

Here is one way, without a regex:

It is:

  1. Parsing the input string with str_getcsv() to separate it into its individual elements, then trimming whitespace around each element with trim() and array_map().
  2. Iterating over each element, searching for a dash. If it finds a dash, it found a range of numbers, so it separates them into the start and end indexes by explode()ing on the dash, and forms the correct range between $start and $end with range(). It then merges that newly formed range with what has already been formed as the result using array_merge().
  3. If, during iteration, it didn't find a dash, it assumes you have a literal number, and adds just that number to the resulting array.

That's it!

$input = '1, 4, 7, 20-25, 31, 46, 100';
$entries = array_map( 'trim', str_getcsv( $input));

$result = array();
foreach( $entries as $entry) {
    if( strpos( $entry, '-') !== false) {
        list( $start, $end) = explode( '-', $entry);
        $result = array_merge( $result, range( trim($start), trim($end)));
    } else {
        $result[] = $entry;
    }
}

You can see from this demo that it produces:

Array (
    [0] => 1
    [1] => 4
    [2] => 7
    [3] => 20
    [4] => 21
    [5] => 22
    [6] => 23
    [7] => 24
    [8] => 25
    [9] => 31
    [10] => 46
    [11] => 100 )

Edit: To form the resulting string, instead of the array, you just need a call to implode(), like so:

echo implode( ', ', $result);

This will produce:

1, 4, 7, 20, 21, 22, 23, 24, 25, 31, 46, 100
nickb
  • 59,313
  • 13
  • 108
  • 143
0

This can be done without the using a regular expression.

  • Get the user input, explode with , as the delimiter, and you'll get an array of all numbers.
  • Now use an if statement to check if the string contains a dash.
  • If it does, explode it again with the delimiter -. Now you'll get two numbers
  • Use range() to create an array of numbers within that range
  • Use implode() to join them by a comma.

As a useful function:

Code:

function fill_string_gaps($input) 
{
    $parts = explode(',', $input);
    $resultArray = array();

    foreach ($parts as $part) {
        if(strpos(trim($part), '-')) {
            list($num1, $num2) = explode('-', $part);
            $expanded_num_array = range($num1, $num2);
            $resultArray = array_merge($resultArray, $expanded_num_array);
        } else {
            $resultArray[] = trim($part);
        }        
    }
        $comma_separated = implode(', ', $resultArray);
        return $comma_separated;

}

Usage:

$input = '1, 4, 7, 20-25, 31, 46, 100';
echo fill_string_gaps($input;)

Test cases:

echo fill_string_gaps('1-5');
echo fill_string_gaps('1-5, 12, 24');
echo fill_string_gaps('2, 2, 4, 5-8');

Output:

1, 2, 3, 4, 5
1, 2, 3, 4, 5, 12, 24
2, 2, 4, 5, 6, 7, 8

See it in action!

Amal Murali
  • 75,622
  • 18
  • 128
  • 150
0
$data = '1, 4, 7, 20-25, 31, 46, 100';
$elts = explode(',', $data);
$res = array();

foreach ($elts as $elt) {
    $elt = trim($elt);

    if (preg_match('/(\d+)-(\d+)/', $elt, $matches) === 1) {
        $res = array_merge($res, range($matches[1], $matches[2]));
    } else {
        $res[] = intval($elt);
    }
}

var_dump($res);
Sean Bright
  • 118,630
  • 17
  • 138
  • 146
0

Simple code :

  1. split string by delimiter , with explode();
  2. remove space from the beginning and end of a string with trim;
  3. function array_map is used so you don't need to do foreach loop just to apply trim() to every element;
  4. create empty array where you will store new elements;
  5. iterate over each number or range with foreach;
  6. do points 1., 2. and 3. again on every iteration;
  7. split string by delimiter - with explode() even if string doesn't have delimiter - in it; result will be array with one or multi elements;
  8. if point 6. has array with multiple elements, that means that there is range involved, so use function range() to create an array containing a range of elements;
  9. store new numbers to point 4. array with array_merge() function;
  10. when point 4. array is full generated; sort values with sort(), so you don't have output like 5, 3, 1, 4 etc. (delete this function if you don't need this functionality);
  11. remove duplicates with array_unique(), so you don't have output like 4, 4, 4, 4, 5 etc. (delete this function if you don't need this functionality)
  12. to convert array back to string like you inputed, use implode() function.

|

function fillGaps($s) {
    $s = array_map('trim', explode(',', $s));
    $ss = [];
    foreach ($s as $n) {
        $n = array_map('trim', explode('-', $n));
        if (count($n) > 1) $n = range($n[0], end($n));
        $ss = array_merge($ss, $n);
    }
    sort($ss); # remove if you don't need sorting
    $ss = array_unique($ss); # remove if duplicates are allowed
    return implode(', ', $ss);
}

Example :

Your example :

echo fillGaps('1,    4, 7, 20   -   25, 31, 46, 100');
# 1, 4, 7, 20, 21, 22, 23, 24, 25, 31, 46, 100

This code will also work for multiple gaps, like :

echo fillGaps('100-105-110');
# 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110

You can even go reverse :

echo fillGaps('10-5');
# 5, 6, 7, 8, 9, 10
# or remove function sort() and output will be 10, 9, 8, 7, 6, 5

Remove duplicates :

echo fillGaps('2-4, 4, 4, 5');
# 2, 3, 4, 5
Glavić
  • 42,781
  • 13
  • 77
  • 107
0

My solution :DEMO HERE

  • First delete spaces using str_replace()
  • explode() string using , to array of integers.
  • explode() every element using - to check if it's a range or just a single integer.
  • if it's a range , loop using for() or range() and add $i to $newArray , else add the element to $newArray.
  • implode() using , and print the result.

PHP code :

<?php
       $str=str_replace(' ', '', '1, 4, 7, 20-25, 31, 46, 100');
       $arr = explode(',',$str);
        foreach($arr as $elem){
           $values=explode('-',$elem);
          if(count($values)!=1)  for($i=$values[0];$i<=$values[1];$i++)   $newArr[]=$i;
          else $newArr[]=$elem;
        }
       echo implode(',',$newArr);
?>

OUTPUT:

1,4,7,20,21,22,23,24,25,31,46,100
Charaf JRA
  • 8,249
  • 1
  • 34
  • 44