I decided for a common development to write my own template bike. Given: Template. Variables in the HTML code fit in the format {var} , {name} , {id} so on. The input template is supplied with an associative array with variables (the key is the name of the variable in the template). With the help of preg_replace replacement.

Stupor began when I tried to implement the conditions:

 {if id == 3} код... {else} другой код... {endif} 

I tried to peep in different template engines as such functionality was implemented, but did not fully understand. Can someone do something like this, or by the example of existing template engines \ frameworks, will it tell you which way to go?

  • /\{\s*if\s+(?P<var>\w+)\s*==\s*(?P<value>\}(код)(\{\s*else\s*\}(<другой код>))?\{\s*endif\s*\} is as regards the regular schedule (I could get it wrong with brackets somewhere) - andy.37
  • somewhere, it seems, there was a more detailed answer, so far. ru.stackoverflow.com/a/450332/16095 - etki
  • one
    Show non-working code - Yuri Negometyanov

2 answers 2

You intrigued me, I wondered if this was solved by simple methods, without complete parsing into lexemes, super-complicated regulars, etc. I proceeded from the assumption that {if} structures can be nested, otherwise the problem was solved too simply. Conditions for if better let it remain simple, as you wrote, otherwise you cannot do without full syntactic analysis.

As a result, I accidentally wrote a working example :)

 function testIF($text) { if(preg_match('/(?<pre>.*?)\{if +(?<p1>[a-zA-Z][a-zA-Z0-9]*) *(?<op>[=!><]+) *(?<p2>.*?) *\}(?<post>.*)/s', $text,$match)): // Корректная конструкция IF встретилась. В $match следующие элементы: // "pre" - текст до IF, "post" - текст после IF // "p1" параметр IF до кода операции, "p2" параметр после кода операции // "op" код операции // Регулярка предполагает, что до кода операции именно название переменной // А коды операций могут состоять из символов =, !, <, > // Если это может быть не так - регулярку стоит поправить $t=testIF($match['post']); // Вызываем себя рекурсивно, для обработки вложенных if // В $t вернется весь текст за нашим if, в котором все вложенные if // уже обработаны, т.е. заменены на текст по условию $pos=strpos($t,"{endif}"); // Действия при ошибке, конечно стоит сделать более разумными, не завершая программу if($pos===FALSE): print("Syntax error endif not found for ..."); die(); endif; $post=substr($t,$pos+7); // $post - текст после endif $t=substr($t,0,$pos); // Внутренний блок if $els=""; if(preg_match('/(.*?)\{else\}(.*)/s',$t,$m2)): $t=$m2[1]; $els=$m2[2]; endif; // Обрабатываем параметры, обработка конечно должна быть более развернутой, с проверкой // на существование переменных, на то а переменные ли это или константы $p1=$VARS[$match['p1']]; $p2=$match['p2']; switch($match['op']) // Обработка операций { // Если условие не прошло, то заменяем текст $t на блок {else}, если был или пустоту case "==": if($p1 != $p2) $t=$els; break; case "!=": if($p1 == $p2) $t=$els; break; } return $match['pre'].$t.$post; endif; return $text; } 
  • Well, I have not yet reached the attachments. I do it incrementally. In case of error (curve syntax in the template), leave as is. So it seems the majority of template engines do. - terantul
  • If anything, I do not have a cycle for several separate IF in one text. The cycle replaces the same recursion, which is responsible for nested constructions. 2 in one :) - Mike

The text is divided into lexemes, rules are written on the basis of lexemes. Here is the tokenizer from the twister https://github.com/twigphp/Twig/blob/1.x/lib/Twig/Lexer.php In a Straustap book, in C ++ books it is good to write about tokens when you program the calculator