Search code examples
phpregexnestedparentheses

Is there a method to omit nested parentheses in regex?


I'm writing a regex function for PHPs' preg_match_all to find all ifs(...) with all its contents from a string. (In my example I've got only one ifs, as it's not re root of the problem.)

Here's what I've got so far:

Pattern: /ifs\(.*?\)/i

String: =iferror(ifs(OR("foo", "bar"),"a",OR("tar", "scar"),"b",OR("lar"),"d"),"c")

Current output: ifs(OR("foo", "bar")

Expected output: ifs(OR("foo", "bar"),"a",OR("tar", "scar"),"b",OR("lar"),"d")

The problem: regex finds first closing parentheses.

Where am I going wrong? And how would you tackle nested parentheses?

Demo: https://regex101.com/r/SgBqbW/1


Solution

  • Actually you can do this thanks to PHPs capability of recursive regexps. This is inspired by this comment on that page:

    $string = '=iferror(ifs(OR("foo", "bar"),"a",OR("tar", OR("scar", "baa")),"b",OR("lar"),"d"),"c")
    blah blah ifs(OR("foo", "bar"),"a") and another one ifs("a", OR("tar", OR("scar", "baa")),"b",OR("lar"),"d")';
    $regex = '/ifs(\(((?>[^()]+)|(?-2))*\))/';
    preg_match_all($regex, $string, $matches);
    print_r($matches[0]);
    

    Output:

    Array (
        [0] => ifs(OR("foo", "bar"),"a",OR("tar", OR("scar", "baa")),"b",OR("lar"),"d")
        [1] => ifs(OR("foo", "bar"),"a")
        [2] => ifs("a", OR("tar", OR("scar", "baa")),"b",OR("lar"),"d") 
    )
    

    Demo on 3v4l.org