1

I have a string in a format like this:

5;1-x;1-2;(1-x;)+

I used 1-x as a notation for all integers from 1 to infinity and (1-x;)+ to mark that the last integer may be repeated any number of times.

Some example strings:

5;1;1;1
5;7;2;7;5;1;9

How can I match these strings with regex and get all the (1-x;)+ matches?

I have tried the following:

preg_match_all('%5;([1-9]{1}[0-9]*);([1-2]);([1-9]{1}[0-9]*;?)+%',
               $str, $matches);

And the result for string "5;1;1;1" is:

array(4) {
  [0]=>
  array(1) {
    [0]=>
    string(7) "5;1;1;1"
  }
  [1]=>
  array(1) {
    [0]=>
    string(1) "1"
  }
  [2]=>
  array(1) {
    [0]=>
    string(1) "1"
  }
  [3]=>
  array(1) {
    [0]=>
    string(1) "1"
  }
}

For the string "5;7;2;7;5;1;9" it is:

array(4) {
  [0]=>
  array(1) {
    [0]=>
    string(13) "5;7;2;7;5;1;9"
  }
  [1]=>
  array(1) {
    [0]=>
    string(1) "7"
  }
  [2]=>
  array(1) {
    [0]=>
    string(1) "2"
  }
  [3]=>
  array(1) {
    [0]=>
    string(1) "9"
  }
}

As you can see, only the last integer from (1-x;)+ is in the matches array, but I want the matches array to contain values 7, 5, 1, and 9, not just the last one. Is this even possible using regex or do I need to use another approach to validate and get values from these strings?

5
  • Please explain how you arrived at the conclusion that you need regular expressions for this. Commented Feb 21, 2013 at 16:50
  • I thought it would be easier than any other method of data validation and parsing the values from the string. Commented Feb 21, 2013 at 16:52
  • 1
    Maybe I'm overlooking something, but explode() won't suffice? Commented Feb 21, 2013 at 16:56
  • 1
    I used regex to match strings in format "1-4;1-x;1-3;1-x" previously so I thought I would expand it. If it's not possible to put these values in the matches array, I think I'll use the regex I have already written to validate that the string is in correct format and then just use explode to get the integer values. Commented Feb 21, 2013 at 16:59
  • 1
    Ah, I see, validation. You can't have a variable number of subpatterns. If you have a quantifier on a subpattern, each match will replace the last one, so its final value will only contain its last match (as you've seen). Commented Feb 21, 2013 at 17:06

2 Answers 2

2

One way

//$str = "5;1;1;1";
$str = "5;7;2;7;5;1;9";
$pattern = '%^5;([1-9]\d*;)[12];((?:[1-9]\d*;?)+)$%';

$str = preg_replace( $pattern, '$1$2', $str, -1, $count );

if ( $count ) {
   print_r( explode( ';', $str ) );
} else {
   echo 'Invalid string';
}

The -1 means no limit to the number of replacements.
$count is the number of replacements made. It will be 1 if the string is valid, or 0 otherwise.

The above assumes a string is still valid if it ends in a ;.

Sign up to request clarification or add additional context in comments.

Comments

0

I honestly would just explode the string and remove the unwanted first and third elements that like this:

$array = explode(';', $string);
$diff_array = array(0 => 'not_used', 2 => 'not_used');
$final_array = array_key_diff($array, $diff_array);

This gives you an array of all the values except the first and third elements which are the ones which you seem to not be interested in.

If you then need to verify that the remaining elements are indeed integers with value >= 1 you could run an array_filter on it like this:

$filtered_array = array_filter($final_array, function($value) {
    if ((string)(int)$value == $value && (int)$value >= 1) return true;
    return false;
}

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.