2013-11-15 3 views
1

Я пытаюсь сделать условные утверждения в системе шаблонов php, но у меня есть некоторые проблемы с его работой.Сложный рекурсивный шаблон регулярного выражения

Мой синтаксис: (condition? value to show if condition is true). Соответствие будет легко выполнено с использованием этого шаблона: \((\w+)\?(.+?)\). Проблема в том, что мне нужно, чтобы она работала рекурсивно.

Я попробовал эти узоры на строку (it should be (a?working(b? with nested conditions).)):

\((\w+)\?(.+?|(?R))\), но он соответствует (a?working(b? with nested conditions) (скачет .) в конце)

\((\w+)\?(.+|(?R))\), но он соответствует (a?working(b? with nested conditions).)) (все до последнего )).

Помогите мне, я застрял.

+0

Мне нужно их захватить. Также ваш шаблон не позволяет использовать символы '()' в группе значений, что не то, что я хочу. – Arrvi

ответ

1

Попробуйте следующую закономерность:

\((\w+)\?([^()]|\((?!\w+\?)|(?R))+\) 

Regex101 Demo

Edit: OK попробуйте изменить шаблон к следующему:

\((\w+)\?(.+|\((?!\w+\?)|(?R))+\) 
      ^^ 

Если это не работает, а , попробуйте изменить .+ на .+?. Если все это не работает для вас, то вы, вероятно, (я думаю, что это лучшее решение) нужно использовать парсер вместо регулярных выражений.

Regex101 Demo 2

+0

Почти. Я забыл упомянуть, что группа значений может содержать символы '()'. Сожалею. Это не упрощает задачу, не так ли? – Arrvi

+0

@Arrvi Я отредактировал свой ответ, проверьте его. –

+0

Нет. Это не работает вообще. И, как вы сказали, я, вероятно, напишу для него парсер. Спасибо, в любом случае. – Arrvi

0

Как сказал @Sniffer, я сделал синтаксический анализатор. Это довольно грязно, но делает работу. Он является частью системного класса шаблонов. $this->rendered - строка, которая анализируется.

const COND_START = '(('; 
const COND_END = '))'; 
const COND_SEP = '?'; 
const COND_NOT = '!'; 
private function parseConditionals() 
{ 
    for (
     $i=0, 
     $level=0, 
     $levelstart=array(0=>0), 
     $levelseparator=array(0=>0), 
     $levelname=array(0=>'__main__'); 
     $i < strlen($this->rendered); 
    ) { 
     $startpos = strpos($this->rendered, self::COND_START, $i); 
     $seppos = strpos($this->rendered, self::COND_SEP, $i); 
     $endpos = strpos($this->rendered, self::COND_END, $i); 

     if (($startpos === FALSE) && ($endpos === FALSE)) { 
      $i = strlen($this->rendered); 
     } elseif (($startpos !== FALSE) && $startpos < $endpos) { 
      if ($seppos < $endpos) { 
       $level++; 
       $levelstart[$level] = $startpos; 
       $levelseparator[$level] = $seppos; 
       $levelname[$level] = substr(
        $this->rendered, 
        $startpos+strlen(self::COND_START), 
        $seppos-$startpos-strlen(self::COND_START) 
       ); 
       $i = $seppos + strlen(self::COND_SEP); 
      } else { 
       $i = $startpos + strlen(self::COND_START); 
      } 
     } else { 
      $originallen = strlen($this->rendered); 
      if ($level > 0) { 
       $not = false; 
       if (strpos($levelname[$level], self::COND_NOT) === 0) { 
        $levelname[$level] = substr($levelname[$level], strlen(self::COND_SEP)); 
        $not = true; 
       } 
       if ( 
        !$this->get($levelname[$level]) == $not 
       ) { 
        $this->rendered = substr_replace(
         $this->rendered, 
         '', 
         $endpos, 
         strlen(self::COND_END) 
        ); 
        $this->rendered = substr_replace(
         $this->rendered, 
         '', 
         $levelstart[$level], 
         $levelseparator[$level]-$levelstart[$level]+strlen(self::COND_SEP) 
        ); 
       } else { 
        $this->rendered = substr_replace(
         $this->rendered, 
         '', 
         $levelstart[$level], 
         $endpos-$levelstart[$level]+strlen(self::COND_END) 
        ); 
       } 
       $level--; 

      } 
      $i = $endpos + strlen(self::COND_END); 
      $i += strlen($this->rendered)-$originallen; 
     } 
    } 
} 
Смежные вопросы