LINUX.ORG.RU

Помогите с регулярным выражением (PHP)

 ,


0

1

Привет всем! В PHP имеется строка примерно такого вида:

$string = 'random text {cmdType:cmdExpression} random text {cmdType:if(true){do something;}do something else;} {cmdType:cmdExpression} random text';

Нужно регулярное выражение для ф-ии preg_match_all, чтобы вычленить все блоки вида {cmdType:cmdExpression}.

Здесь cmdType - это просто какая-то строка, обозначающая тип команды (что-то вроде «regexp», «php» и пр)

cmdExpression - это какой-то код (непосредственно код php, регулярное выражение или что-то ещё).

Составил вот такое:

$regex = '#{([^:]+):(.*)}(?=([^}]*\{\w+\:|$|[^{}]+$))#iU';
$r = preg_match_all($regex, $string, $matches);
var_dump($r);

Возвращает в данном случае примерно такой результат:

array(4) {
  [0]=>
  array(3) {
    [0]=>
    string(23) "{cmdType:cmdExpression}"
    [1]=>
    string(50) "{cmdType:if(true){do something;}do something else}"
    [2]=>
    string(23) "{cmdType:cmdExpression}"
  }
  [1]=>
  array(3) {
    [0]=>
    string(7) "cmdType"
    [1]=>
    string(7) "cmdType"
    [2]=>
    string(7) "cmdType"
  }
  [2]=>
  array(3) {
    [0]=>
    string(13) "cmdExpression"
    [1]=>
    string(40) "if(true){do something;}do something else"
    [2]=>
    string(13) "cmdExpression"
  }
  [3]=>
  array(3) {
    [0]=>
    string(22) " random text {cmdType:"
    [1]=>
    string(10) " {cmdType:"
    [2]=>
    string(12) " random text"
  }
}

Всё прекрасно работает, вот только минус в том, что в части «random text» не должны встречаться фигурные скобки, поскольку тогда логика работы моего регулярного выражения нарушается. Например (добавлена закрывающая фигурная скобка во второй блок random text):

$string2 = 'random text {cmdType:cmdExpression} random } text {cmdType:if(true){do something;}do something else} {cmdType:cmdExpression} random text';
$regex = '#{([^:]+):(.*)}(?=([^}]*\{\w+\:|$|[^{}]+$))#iU';
$r = preg_match_all($regex, $string, $matches);
var_dump($r);

Выводит:


array(4) {
  [0]=>
  array(3) {
    [0]=>
    string(32) "{cmdType:cmdExpression} random }"
    [1]=>
    string(50) "{cmdType:if(true){do something;}do something else}"
    [2]=>
    string(23) "{cmdType:cmdExpression}"
  }
  [1]=>
  array(3) {
    [0]=>
    string(7) "cmdType"
    [1]=>
    string(7) "cmdType"
    [2]=>
    string(7) "cmdType"
  }
  [2]=>
  array(3) {
    [0]=>
    string(22) "cmdExpression} random "
    [1]=>
    string(40) "if(true){do something;}do something else"
    [2]=>
    string(13) "cmdExpression"
  }
  [3]=>
  array(3) {
    [0]=>
    string(15) " text {cmdType:"
    [1]=>
    string(10) " {cmdType:"
    [2]=>
    string(12) " random text"
  }
}

Вместо первого «{cmdType:cmdExpression}» получили «{cmdType:cmdExpression} random }». Так не хотелось бы. Кто-нибудь может помочь составить вариант выражения, который обходит это ограничение (позволяет использовать фигурные скобки в части random text)?

Ответ на: комментарий от Novascriptum

Что регуляркой ты это распарсить не сможешь

buddhist ★★★★★
()
Ответ на: комментарий от goingUp

Прямо чудеса, мало того, что работает, так ещё и на порядок лаконичнее. Помогите понять ваш синтаксис вот этого места: ([^{}]+|{[^{}]+})+

Идёт выбор 1-го или 2-го варианта в скобках, разделённых вертикальной чертой. До черты - последовательность из любых символов, кроме фигурных скобок. После - то же самое, но в фигурных скобках. А плюс после скобок означает, что идёт повторение этих двух подпоследовательностей в любом сочетании, так?

Novascriptum
() автор топика
Ответ на: комментарий от Novascriptum

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

{(\w+):([^{}]+|{(?2)+})+}

goingUp ★★★★★
()
Ответ на: комментарий от anonymous

Да, они будут достаточно простыми. И, кстати, проверил, даже с $a=«{b+c}» данное выражение справляется на ура. Но спасибо за участие и ссылку!

Novascriptum
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.