PHP regular expression to replace nested () with []

我与影子孤独终老i 提交于 2020-01-11 10:25:14

问题


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)";
|improve this question

回答1:


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);



回答2:


$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];
}



回答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...




回答4:


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.




回答5:


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 (e.g. (foo (bar)).



来源:https://stackoverflow.com/questions/3182867/php-regular-expression-to-replace-nested-with

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!