Есть строка:
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]
);
Предлагаю не самое простое решение, но это единственное решение, основанное на одном регулярном выражении. Чтобы найти несколько совпадений внутри какой-то определённой подстроки, нужно использовать шаблон на основе оператора \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]
)
)
Я не уверен, но мне кажется тут придется пройтись регулярным выражением два раза, т.к. иначе у все Ваши "элементы тегов" (или что это? как Вы это называете-то?) будут в одной единой куче и их неприятно будет разбирать.
Первый раз делаете:
preg_match_all('/{msg (.*?)}/', $a, $matches);
Затем делаете:
foreach($matches[1] as $match) {
preg_match_all('/\[.*?\]|\b[^\s]+\b/', $match, $sub_matches);
// делаете что хотели с $sub_matches[0];
}
В одну регулярку такой результат не выйдет получить. Почему ответ здесь 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]
)
)
Сборка персонального компьютера от Artline: умный выбор для современных пользователей