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\$
13
  • \$\begingroup\$ Character sets [...(...] come to mind. \$\endgroup\$
    – vnp
    Commented Jun 28, 2017 at 20:50
  • \$\begingroup\$ @vnp but it can't tell if the if the open parentheses are escaped \$\endgroup\$
    – Benjaco
    Commented Jun 28, 2017 at 20:55
  • \$\begingroup\$ I mean you will count such ( as a capturing one. \$\endgroup\$
    – vnp
    Commented Jun 28, 2017 at 20:56
  • 1
    \$\begingroup\$ What are you really trying to achieve? You are trying to build a regex parser? \$\endgroup\$
    – Mike Brant
    Commented Jun 28, 2017 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
    Commented Jun 28, 2017 at 22:00

1 Answer 1

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\$
3
  • \$\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
    Commented Jun 28, 2017 at 20:44
  • \$\begingroup\$ but I have forgotten to remove non-capturing groups, thank you for that insight \$\endgroup\$
    – Benjaco
    Commented Jun 28, 2017 at 21:32
  • \$\begingroup\$ I will force the developers to use none capture groups \$\endgroup\$
    – Benjaco
    Commented Jun 30, 2017 at 11:15

Your Answer

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

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