3
\$\begingroup\$

I am trying to find the number of capture groups for a regular expression using this PHP function.

/**
 * Finds the number of groups in a regular expression
 * @param $regexPatten string The regular expression
 * @return int Returns the number of groups inside the regular expression
 */
public static function numOfGroups($regexPatten)
{
    $regexPatten = str_replace('\\\\', "", $regexPatten); // remove all escaped backslashes
    $regexPatten = str_replace('\\(', "", $regexPatten); // remove all escaped open parentheses
    $regexPatten = str_replace('(?:', "", $regexPatten); // remove all none capture groups

    return substr_count($regexPatten, "("); // count the remaining opening parentheses
}

And here is my test:

var_dump(Parser::numOfGroups("(test)")); // 1  --  will match: test
var_dump(Parser::numOfGroups("\((test)\)")); // 1  --  will match: (test)
var_dump(Parser::numOfGroups("\\\\\((test)\\\\(\d+)\)")); // 2  --  plain regex: \\\((test)\\(\d+)\)  --  will match: \(test\343)
var_dump(Parser::numOfGroups("((?:test(?: )?)+)")); // 1  --  will match: test test

Is there any use cases I have forgotten?

\$\endgroup\$
  • \$\begingroup\$ Character sets [...(...] come to mind. \$\endgroup\$ – vnp Jun 28 '17 at 20:50
  • \$\begingroup\$ @vnp but it can't tell if the if the open parentheses are escaped \$\endgroup\$ – Benjaco Jun 28 '17 at 20:55
  • \$\begingroup\$ I mean you will count such ( as a capturing one. \$\endgroup\$ – vnp Jun 28 '17 at 20:56
  • 1
    \$\begingroup\$ What are you really trying to achieve? You are trying to build a regex parser? \$\endgroup\$ – Mike Brant Jun 28 '17 at 21:43
  • 1
    \$\begingroup\$ But why? Are you expecting to get arbitrary regular expression passed to this method that you need to get metadata for? Do you really need to know this information before the regex is run (at which point you can typically easily count the number of capturing groups if there is a pattern match)? \$\endgroup\$ – Mike Brant Jun 28 '17 at 22:00
2
\$\begingroup\$

You might consider non-capturing groups

(?:/*pattern*/)

These will match your regex but won't normally be operated on in whatever code is running the regex you're evaluating.

\$\endgroup\$
  • \$\begingroup\$ This is not a bad idea, but the function is part of a router, and I can imagine people who use the router are going to forget this :( \$\endgroup\$ – Benjaco Jun 28 '17 at 20:44
  • \$\begingroup\$ but I have forgotten to remove non-capturing groups, thank you for that insight \$\endgroup\$ – Benjaco Jun 28 '17 at 21:32
  • \$\begingroup\$ I will force the developers to use none capture groups \$\endgroup\$ – Benjaco Jun 30 '17 at 11:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.