Сложное регулярное выражение

109
19 февраля 2018, 03:38

Есть строка:

text {msg ru key} text text {msg key [m=1,p=1]} text {msg ru key [m=la la|p=1]} text

Как видим в ней есть тег {msg}.

Как составить регулярку так, чтобы она разбирала этот тег?
Если тег написан так: {msg ru key} то тогда вывод нужно такой:

array(
   0 => ru,
   1 => key
);

Если тег написан так: {msg ru key [m=la la|p=1]} то тогда вывод нужно такой:

array(
   0 => ru,
   1 => key,
   2 => [m=la la|p=1]
);

Если тег написан так: {msg key [m=la la|p=1]} то тогда вывод нужно такой:

array(
   0 => key,
   1 => [m=la la|p=1]
);
Answer 1

Предлагаю не самое простое решение, но это единственное решение, основанное на одном регулярном выражении. Чтобы найти несколько совпадений внутри какой-то определённой подстроки, нужно использовать шаблон на основе оператора \G (=начало строки или конец предыдущего совпадения).

'~(?:(?!^)\G|{msg)\s+\K(?:\w+|\[[^][]*])(?=[^}]*})~'

См. демо регулярного выражения.

  • (?:(?!^)\G|{msg) - конец предыдущего совпадения ((?!^)\G) или (|) подстрока {msg
  • \s+ - 1 и более пробельных символов
  • \K - оператор, очищающий буфер текущего совпадения (будто ничего не нашли до сих пор)
  • (?:\w+|\[[^][]*]) - одно из двух:
    • \w+ - 1 и более букв, цифр или _
    • | - или
    • \[[^][]*] - подстрока вида [...] (между скобками не может быть других скобок)
  • (?=[^}]*}) - (блок предварительного просмотра вперёд) после данного места в строке не может быть 0 и более символов, отличных от }, а потом }.

Если просто использовать это выражение для строки, в которой есть несколько подстрок {msg...}, найдены будут все совпадения, но они не будут группированы (см. PHP-демо). Чтобы их сгруппировать, надо использовать немного кода:

$re = '/(?:(?!^)\G|({msg))\s+\K(?:\w+|\[[^][]*])(?=[^}]*})/';
$str = 'text {msg ru key} text text {msg key [m=1,p=1]} text {msg ru key [m=la la|p=1]} text';
$results = [];
$tmp = -1;
preg_replace_callback($re, function($m) use (&$results, &$tmp) {
    if (!empty($m[1])) {
        array_push($results, array($m[0]));
        $tmp=$tmp+1;
    } else {
        $results[$tmp][] = $m[0];
    }
}, $str);
print_r($results);

См. PHP-демо. Результат:

Array
(
    [0] => Array
        (
            [0] => ru
            [1] => key
        )
    [1] => Array
        (
            [0] => key
            [1] => [m=1,p=1]
        )
    [2] => Array
        (
            [0] => ru
            [1] => key
            [2] => [m=la la|p=1]
        )
)
Answer 2

Я не уверен, но мне кажется тут придется пройтись регулярным выражением два раза, т.к. иначе у все Ваши "элементы тегов" (или что это? как Вы это называете-то?) будут в одной единой куче и их неприятно будет разбирать.

Первый раз делаете:

preg_match_all('/{msg (.*?)}/', $a, $matches);

Затем делаете:

foreach($matches[1] as $match) {
    preg_match_all('/\[.*?\]|\b[^\s]+\b/', $match, $sub_matches);
    // делаете что хотели с $sub_matches[0];
}
Answer 3

В одну регулярку такой результат не выйдет получить. Почему ответ здесь PHP has no support for captures of the same group

$string = 'text {msg ru key} text text {msg key [m=1,p=1]} text {msg ru key [m=la la|p=1]} text';
preg_match_all('#(?<={)[^}]+(?=})#', $string, $matches);
$result = [];
foreach($matches[0] as $item_match){
    preg_match_all('#(\w+)|(\[[^]]+\])#', $item_match, $sub_matches);
    $result[] = $sub_matches[0];
}
print_r($result);

Вывод

Array
(
    [0] => Array
        (
            [0] => msg
            [1] => ru
            [2] => key
        )
    [1] => Array
        (
            [0] => msg
            [1] => key
            [2] => [m=1,p=1]
        )
    [2] => Array
        (
            [0] => msg
            [1] => ru
            [2] => key
            [3] => [m=la la|p=1]
        )
)
READ ALSO
Чем отличается встроенная функция С++ от макроса Си?

Чем отличается встроенная функция С++ от макроса Си?

Как я понял, встроенная функция в С++ это аналог макроса СиНо в книге прочел, что встраиванием кода встроенной функции занимается компилятор,...

125
Не работает консоль в Visual Studio 2017

Не работает консоль в Visual Studio 2017

Когда делаю отладку консоль включается, но в нее ничего не записываетсяЯ перекачивал Visual Studio 4 раза и все равно не работает

153
Фоновый ввод информации C++

Фоновый ввод информации C++

Как сделать так чтобы программа работала, скажем циклом, но ждала ввода информации? Допустим у нас есть бесконечный цикл, который перечисляет...

131