0

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.

1
  • I didn't vote you down. But it happened because you've provided no evidence of actually trying your own solutions first, you are just asking others to do your [home]work for you. Commented Feb 5, 2013 at 23:36

3 Answers 3

1
$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)
Sign up to request clarification or add additional context in comments.

2 Comments

Is there a direct way to achieve this grouping without looping through the array?
Yes, add PREG_SET_ORDER to the preg_match_all call. I edited my answer.
1

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

Comments

-1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.