preg_match_all разделить условное выражение

У меня есть данные в таком формате:

Randomtext1(random2, random4) Randomtext2 (ran dom) Randomtext3 Randomtext4 (random5,random7,random8) Randomtext5 (Randomtext4 (random5,random7,random8), random10) Randomtext11()

с этим:

preg_match_all("/\b\w+\b(?:\s*\(.*?\)|)/",$text,$matches);

я получаю:

0 => 'Randomtext1(random2, random4)',
1 => 'Randomtext2 (ran dom)',
2 => 'Randomtext3',
3 => 'Randomtext4 (random5,random7,random8)',
4 => 'Randomtext5 (Randomtext4 (random5,random7,random8)',
5 => 'random10',
6 => 'Randomtext11()',

но я хочу

0 => 'Randomtext1(random2, random4)',
1 => 'Randomtext2 (ran dom)',
2 => 'Randomtext3',
3 => 'Randomtext4 (random5,random7,random8)'
4 => 'Randomtext5 (Randomtext4 (random5,random7,random8), random10)' 
5 => 'Randomtext11()'

Любые идеи?


person francis    schedule 11.10.2017    source источник
comment
Я хотел бы сделать это за несколько строк по сравнению с регулярным выражением oneliner. Ищите способы расстаться.   -  person sniperd    schedule 11.10.2017


Ответы (1)


Вам нужен рекурсивный шаблон для обработки вложенных скобок:

if ( preg_match_all('~\w+(?:\s*(\([^()]*+(?:(?1)[^()]*)*+\)))?~', $text, $matches) )
    print_r($matches[0]);

демонстрация

Детали:

~    # delimiter
\w+
(?:
    \s*
    ( # capture group 1
        \(
        [^()]*+  # all that isn't a round bracket 
                 # (possessive quantifier *+ to prevent too many backtracking
                 # steps in case of badly formatted string)
        (?:
            (?1) # recursion in the capture group 1
            [^()]*
        )*+
        \)
     )  # close the capture group 1
)? # to make the group optional (instead of "|)")
~

Обратите внимание, что вам не нужно добавлять границы слов вокруг \w+.

person Casimir et Hippolyte    schedule 11.10.2017
comment
Если у меня буква с ударением, например: é, то результат плохой. У тебя есть решение ? - person francis; 11.10.2017
comment
@francis: Да, конечно. Используйте модификатор u, чтобы расширить класс символов \w до символов Юникода. - person Casimir et Hippolyte; 11.10.2017
comment
Последний вопрос, я пытаюсь использовать этот интервал ((#[Météo]#-30)/100) #2572# == 1 || #83# › 0. Результат хороший, но символ '#' вместо '#83#' потерян. Спасибо за быстрый ответ - person francis; 12.10.2017
comment
@francis: твой вопрос неясен. Эта строка выходит за рамки заданного вами вопроса и имеет совершенно другой формат. Если мой ответ соответствует вашему первоначальному вопросу, примите его, и если вы хотите обработать другие случаи, задайте новый вопрос с четким описанием возможных строк с ожидаемыми результатами. - person Casimir et Hippolyte; 12.10.2017
comment
@francis: другое дело, если ваша цель - проанализировать язык программирования, не тратьте время на регулярное выражение и ищите парсер. - person Casimir et Hippolyte; 12.10.2017
comment
K, я опубликую новый вопрос. Спасибо. - person francis; 12.10.2017