PHP регулярное выражение для замены nested () на [] - PullRequest
2 голосов
/ 06 июля 2010

Я пытаюсь сопоставить строку, см. Пример, такой, что вложенные parantheses () заменяются на [], чтобы не разбить парсер где-то еще.В этом случае я хотел бы заменить $ myStr на «Arman; Dario (10040 Druento (Turin), IT)» ... ...

Заранее спасибо!

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

Очевидно, мне также нужно переключить match_all для замены.

Подведем итог:

ВХОД

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

ВЫХОД

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

Ответы [ 5 ]

4 голосов
/ 06 июля 2010

Вы не можете делать это надежно с регулярными выражениями.Если вы все равно решите использовать этот метод, ответ зависит от того, какие предположения вы хотите сделать относительно ввода.Например, если вы хотите предположить, что самые внутренние скобки можно заменить, ответ прост:

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

Если вы специально ищете вложенные скобки, попробуйте:

1 голос
/ 06 июля 2010

Вы можете сделать это с помощью цикла for и массива, действующего как стек. Когда вы найдете открытую скобку, нажмите на стопку, и когда вы найдете закрывающую скобку, выскочившую из стопки. Длина стека скажет вам, если вы должны заменить текущую скобку.

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

Вот несколько примеров ввода и вывода:

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

Это не особенно эффективный алгоритм (построение строкового char с помощью char), и он может быть немного умнее с несопоставленными скобками, но в любом случае ...

1 голос
/ 06 июля 2010
$myStr = "Arman; Dario (10040 Druento (Turin), IT)";

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

Вы можете запустить его до тех пор, пока он не будет соответствовать

while( preg_match_all($pattern,$myStr,$matches)) )
{
    $mystr = $matches[1] . '[' . $matches[2] . ']' . $matches[3];
}
0 голосов
/ 06 июля 2010

Вложенные скобки не могут быть сопоставлены с обычной грамматикой . Поэтому истинное регулярное выражение не сможет соответствовать вложенным круглым скобкам произвольной глубины. См. Сообщение Можно ли использовать регулярные выражения для сопоставления с вложенными скобками? для более подробного объяснения.

К счастью, регулярные выражения в PHP на самом деле не регулярные . «Регулярные» выражения Perl поддерживают рекурсивные шаблоны, как описано в PHP.net . Для этой конкретной проблемы, вы рассматривали вопрос о замене элементов по отдельности на str_replace()? Это может произойти только в том случае, если вы можете встретить непревзойденные открывающие и закрывающие скобки (например, (foo (bar)).

0 голосов
/ 06 июля 2010

Для соответствия вложенных скобок требуется синтаксический анализатор для контекстно-свободной грамматики.Вы не можете сделать это с помощью регулярного выражения.

Lime - это синтаксический анализатор, написанный на PHP, но, похоже, он заброшен, и его документации крайне не хватает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...