简体   繁体   中英

PHP regular expression to replace nested () with []

I am trying to match a string, see example, such that a nested parantheses () is replaced by [] so to not break a parser somewhere else. In this case, I would like to replace the $myStr with "Arman; Dario (10040 Druento (Turin), IT)" ...

Thanks in advance!

monte

{x:

  $myStr = "Arman; Dario (10040 Druento (Turin), IT)";
    $pattern = "/(\()([a-z,A-Z0-9_\&\/\'\-\,\;\:\.\s^\)]+)(\))/";
    if (preg_match_all($pattern,$myStr,$matches))
        {
            print_r($matches);
        }

Obviously, I also need to switch match_all to replace.

To summarize:

INPUT

$myStr = "Arman; Dario (10040 Druento (Turin), IT)";

OUTPUT

$myStr = "Arman; Dario (10040 Druento [Turin], IT)";

You can't do this reliably with regular expressions. If you choose to go with this method anyway, the answer depends on what assumptions you're willing to make about the input. If, for example, you're willing to assume the innermost parentheses can be replaced, the answer is easy:

preg_replace('!\(([^()]*)\)!', '{$1}', $input);

If you're specifically looking for nested parentheses, try:

preg_replace('!\(([^()]*)\(([^()]*)\)([^()]*)\)!', '($1{$2}$3)', $input);
$myStr = "Arman; Dario (10040 Druento (Turin), IT)";

$pattern = "/(.*\(.*)\(([^()]+)\)(.*)/";
if (preg_match_all($pattern,$myStr,$matches))
    {
        print( $matches[1] . '[' . $matches[2] . ']' . $matches[3] );
    }

You can run it through that until it doesn't match

while( preg_match_all($pattern,$myStr,$matches)) )
{
    $mystr = $matches[1] . '[' . $matches[2] . ']' . $matches[3];
}

You could do this with a for loop and an array acting as a stack. When you find an open bracket, push onto the stack, and when you find a closing bracket pop from the stack. The length of the stack will tell you if you should replace the current bracket.

$stack = array();
$str = "Arman; Dario (10040 Druento (Turin), IT)";
$out = "";

for ($i = 0, $l = strlen($str); $i < $l; ++$i) {
    if ($str[$i] == "(") {
        $stack[] = true;

        if (count($stack) % 2) { // alternate between ( and [
            $out .= "(";
        } else {
            $out .= "[";
        }
    } else if ($str[$i] == ")") {
        if (count($stack) % 2) {
            $out .= ")";
        } else {
            $out .= "]";
        }
        array_pop($stack);
    } else {
        $out .= $str[$i];
    }
}

Here's some sample input and output:

Arman; Dario (10040 Druento (Turin), IT)
Arman; Dario (10040 Druento [Turin], IT)

a ( b ( c ( d ) ) e )
a ( b [ c ( d ) ] e )

a (b  (c) (d) (e) )
a (b  [c] [d] [e] )

a (b (c (d) (e) (f)))
a (b [c (d) (e) (f)])

It's not a particularly efficient algorithm (building the string char by char), and it could be a bit smarter about unmatched brackets, but anyway...

Matching nested parentheses requires a parser for a context-free grammar. You can't do it with a regular expression.

Lime is a parser written in PHP, but it appears to be abandonware, and its documentation is severely lacking.

Nested parenthesis cannot be matched with a regular grammar . Therefore, a true regular expression will not be able to match nested parenthesis of an arbitrary depth. See the post Can regular expressions be used to match nested parenthesis? for a more detailed explanation.

Thankfully, regular expressions in PHP are not actually regular . Perl "regular" expressions support recursive patterns, as described on PHP.net . For this particular problem, have you considered replacing the elements individually with str_replace() ? This would only fail if you can encounter unmatched opening and closing parenthesis (eg (foo (bar) ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM