Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/regex/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 如何用正则表达式捕获嵌套的{%if…%}{%endif%}语句_Php_Regex_Preg Replace Callback - Fatal编程技术网

Php 如何用正则表达式捕获嵌套的{%if…%}{%endif%}语句

Php 如何用正则表达式捕获嵌套的{%if…%}{%endif%}语句,php,regex,preg-replace-callback,Php,Regex,Preg Replace Callback,这就是我现在得到的: /{%if(+?)%}(.*){%endif%}/gusi 它可以捕捉多个if语句等 IMG: 但是当我进行嵌套时,if中的if会在第一次出现{%endif%}时停止 IMG: 是否有一种方法可以捕获与{%if…%}语句一样多的{%endif%}语句,如果有,如何捕获?将模式更改为: 工作示例: 然而,这是一个坏主意:该模式缺少许多情况,而这些情况实际上是解析器中的错误。以下是几个常见的例子: 评论: {% if aaa %} 123 <!-- {% endif %

这就是我现在得到的:

/{%if(+?)%}(.*){%endif%}/gusi

它可以捕捉多个if语句等

IMG:

但是当我进行嵌套时,if中的if会在第一次出现{%endif%}时停止

IMG:


是否有一种方法可以捕获与{%if…%}语句一样多的{%endif%}语句,如果有,如何捕获?

将模式更改为:

工作示例:

然而,这是一个坏主意:该模式缺少许多情况,而这些情况实际上是解析器中的错误。以下是几个常见的例子:

  • 评论

    {% if aaa %}
    123
    <!-- {% endif %} -->
    {% endif %}
    
  • 转义字符(您确实需要转义字符,对吗?)

  • 无效输入
    如果解析器能够在无效输入上相对良好地工作,并指向错误的正确位置,那就太好了


    • 不要使用regexen,使用现有的细枝解析器。下面是我编写的一个提取器示例,它解析自定义标记并提取它们:

      lexer的工作是将细枝源代码转换为对象;如果需要挂接到该流程中,您可以对其进行扩展:

      class My_Twig_Lexer extends Twig_Lexer {
      
          ...
      
          /**
           * Overrides lexComment by saving comment tokens into $this->commentTokens
           * instead of just ignoring them.
           */
          protected function lexComment() {
              if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
                  throw new Twig_Error_Syntax('Unclosed comment', $this->lineno, $this->filename);
              }
              $value = substr($this->code, $this->cursor, $match[0][1] - $this->cursor);
              $token = new Twig_Extensions_Extension_Gettext_Token(Twig_Extensions_Extension_Gettext_Token::COMMENT, $value, $this->lineno);
              $this->commentTokens[] = $token;
              $this->moveCursor($value . $match[0][0]);
          }
      
          ...
      
      }
      
      通常,细枝注释节点被细枝丢弃,此lexer将保存它们

      但是,您主要关心的是如何使用解析器:

      $twig   = new Twig_Environment(new Twig_Loader_String);
      $lexer  = new My_Twig_Lexer($twig);
      $parser = new Twig_Parser($twig);
      
      $source = file_get_contents($file);
      $tokens = $lexer->tokenize($source);
      $node   = $parser->parse($tokens);
      processNode($node);
      
      $node
      这里是节点树的根节点,这些节点以面向对象的方式表示细枝源,所有节点都已正确解析。您只需处理此树,而不必担心生成它所使用的确切语法:

       processNode(Twig_NodeInterface $node) {
            switch (true) {
                case $node instanceof Twig_Node_Expression_Function :
                    processFunctionNode($node);
                    break;
                case $node instanceof Twig_Node_Expression_Filter :
                    processFilterNode($node);
                    break;
            }
      
            foreach ($node as $child) {
                if ($child instanceof Twig_NodeInterface) {
                    processNode($child);
                }
            }
       }
      

      只需遍历它,直到找到要查找的节点类型并获取其信息。好好玩玩吧。这个示例代码可能有点过时,也可能没有。无论如何,您必须深入细枝解析器源代码才能理解它。

      您使用的是什么语言?PHP正则表达式。(preg_uu函数)我在标签中添加了这个,但是有人(@Michael9)说我最好删除它。您真的不应该为此使用regexen,解析器会做得更好更精确。这看起来像细枝语法;如果是这样的话,Twig有一个奇妙的解析器,您可以劫持/扩展/适用于此任务。@deceze这就是它的确切用途。我正在尝试编写一个可配置的模板解析器,您可以将其设置为读取变量,例如{{var}}或{$var},或者以您想要的方式读取。虽然我从未尝试过使用块和其他东西,但对我来说似乎太复杂了,它看起来也类似于Smarty模板语法。如果是现有模板语言,请使用提供的/本机库/扩展。如果您正在尝试使用自己的模板语言,最好在遇到更多问题之前立即停止,并使用现有的模板引擎。模板化需要对可能的输入流进行广泛的关注和测试,除了一些简单的正则表达式之外,还需要定义非常好的lexer/parser/tokenizer规则集。很抱歉,我不能接受两个最佳答案,所以我选择了最简单的一个。你的解释真的很好,但我正在寻找一个有效的递归正则表达式模式,也是为了了解它们是如何工作的。尽管如此,还是要感谢你的小树枝(不知道如何称呼它),你会对正则表达式的解决方案感到满意,直到有一天它在某些特殊情况下几乎不可避免地破裂。或者直到你需要扩展它。只是说…:o) 是的,我知道。这就是为什么我要使用它:我经常创建小型PHP项目。因为理解PHP和HTML相互传递时发生的事情很痛苦,所以我总是使用模板引擎。因为大多数模板引擎对于简单的项目来说太复杂了,所以我决定只制作自己的模板引擎来完成简单的事情,比如if-then-else和循环。它不适用于任何复杂的事情。对于complex,我已经使用了Twig,这也是我选择该语法的原因。节省了我自己设计的时间。@aronvanwillige-避免php/HTML流问题的诀窍是不要将两者交织在一起。一个好的模板引擎应该比尝试创建和解析自己的模板引擎要轻松。好吧,这是一个公认的答案:)虽然它没有回答我的问题,但你似乎真的很喜欢它…这是一段非常好的代码,Kobi。我找到了一些问题的解决办法:1。评论:这些可以在任何魔法发生之前过滤掉<代码>preg_replace('//usi','$context)preg\u replace\u callback3将转义字符预先更改为HTML实体。字符串文字:与转义字符相同。不过,您的示例并没有太大意义,因为在条件的(HTML)输出中使用了逻辑。对于操作,您有什么建议吗?要么是一个坚实的模板框架,要么是一组定义良好的工具,用于实现lexer/parser/tokenizer的自定义词典?只是想一想,与其让他们认为他们需要将你的答案视为挑战/障碍,不如指向低级工具。@Anthony-我的答案是159个字符,后面是605个字符的警告(这些只是示例)。我认为这就足够了,尤其是德塞兹的回答。这很公平。我没想到聊天会如此活跃,我想OP可能需要一些指导。
      class My_Twig_Lexer extends Twig_Lexer {
      
          ...
      
          /**
           * Overrides lexComment by saving comment tokens into $this->commentTokens
           * instead of just ignoring them.
           */
          protected function lexComment() {
              if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
                  throw new Twig_Error_Syntax('Unclosed comment', $this->lineno, $this->filename);
              }
              $value = substr($this->code, $this->cursor, $match[0][1] - $this->cursor);
              $token = new Twig_Extensions_Extension_Gettext_Token(Twig_Extensions_Extension_Gettext_Token::COMMENT, $value, $this->lineno);
              $this->commentTokens[] = $token;
              $this->moveCursor($value . $match[0][0]);
          }
      
          ...
      
      }
      
      $twig   = new Twig_Environment(new Twig_Loader_String);
      $lexer  = new My_Twig_Lexer($twig);
      $parser = new Twig_Parser($twig);
      
      $source = file_get_contents($file);
      $tokens = $lexer->tokenize($source);
      $node   = $parser->parse($tokens);
      processNode($node);
      
       processNode(Twig_NodeInterface $node) {
            switch (true) {
                case $node instanceof Twig_Node_Expression_Function :
                    processFunctionNode($node);
                    break;
                case $node instanceof Twig_Node_Expression_Filter :
                    processFilterNode($node);
                    break;
            }
      
            foreach ($node as $child) {
                if ($child instanceof Twig_NodeInterface) {
                    processNode($child);
                }
            }
       }