Home > Software design >  preg_match unconditionally return key for unmatched optional capture group
preg_match unconditionally return key for unmatched optional capture group

Time:02-11

$pattern = "/^(?<animal>DOG|CAT)?(?<color>BLUE|RED)?$/i";
$str = "DOG";

preg_match($pattern, $str, $matches);
$matches = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);


// $str = "dog" returns [animal] => DOG

//$str = "dogBLUE" returns [animal] => dog and [color] => BLUE
print_r($matches);

I have an example http://sandbox.onlinephpfunctions.com/code/2428bc68adcf9929557d86dc1ae72552c3681b58 too

Both named capture groups are optional and so keys will only be returned if a match is found.

My Question

How can I unconditionally return keys for any of my possible named capture groups? Empty String '' would be great if it group ain't found.

Input of "DOG" resulting in [animal] => 'DOG', [color] => '' is what I'm looking for.

I was hoping for a flag on preg_match to do this, but couldn't find anything.

Update: I just want to avoid doing isset($matches[OPTIONAL_GROUP])

Thanks!

CodePudding user response:

Allow duplicate named captures (with J or with (?J) for PHP < 7.3) and initialize groups you need at the start of the pattern:

~ (?<animal>) (?<color>)
  
  ^ (?<animal>DOG|CAT)? (?<color>RED|BLUE)? $
~xiJ

demo

Advantage: you can choose the order of groups in the result array.


Or without to change your pattern:

$arr = ['animal' => '', 'color' => ''];

$result = array_intersect_key($matches, $arr)   $arr;

demo

Notice: array_intersect_key($matches $arr, $arr) produces exactly the same result.

CodePudding user response:

You can use andre at koethur dot de's solution:

$pattern = "/^(?<animal>DOG|CAT)?(?<color>BLUE|RED)?$/i";
$str = "DOG";

if (preg_match($pattern, $str, $matches)) {
  $matches = array_merge(array('animal' => '', 'color' => ''), $matches);
  $matches = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);
  print_r($matches);
}

See the PHP demo. Output:

Array
(
    [animal] => DOG
    [color] => 
)

The idea is that you need to "assign a name to all subpatterns you are interested in, and merge $matches afterwards with an constant array containing some reasonable default values".

  • Related