正则表达式 - 获取元素以呈现if语句

时间:2016-06-12 08:47:18

标签: php regex preg-match-all

我正在设计一个脚本并尝试在php中使用if构造而不使用eval

仍然不完整但是爆破,要做一个模板引擎,"如果"引擎的一部分。不允许赋值运算符,但我需要测试值而不允许使用php代码注入,正好不使用eval 它需要在变量之间进行单独操作以防止注入攻击

正则表达式必须捕获

[if:(a+b-c/d*e)|(x-y)&!(z%3=0)]
    output
[elseif:('b'+'atman'='batman')]
    output2
[elseif:('b'+'atman'='batman')]
    output3
[elseif:('b'+'atman'='batman')]
    output4
[else]
    output5
[endif]

[if:(a+b-c/d*e)|(x-y)&!(z%3=0)]
    output6
[else]
    output7
[endif]

以下方法用于获取if,elseif,else和endif块以及条件语句:

$regex = '^\h*\[if:(.*)\]\R(?<if>(?:(?!\[elseif)[\s\S])+)\R^\h*\[elseif:(.*)\]\R(?<elseif>(?:(?!\[else)[\s\S])+)\R^\h*\[else.*\]\R(?<else>(?:(?!\[endif)[\s\S])+)\R^\[endif\]~xm';

请帮助选择elseif和其他。

然后使用条件语句,我可以通过以下方式获取操作:

$regex = '~([^\^=<>+\-%/!&|()*]+)([\^+\-%/!|&*])([^\^=<>+\-%/!&|()*]*)~';

然而,它只会配对它们,缺少每个第三个操作员......

感谢您的帮助。

2 个答案:

答案 0 :(得分:7)

编辑在底部添加了一个简单的if / elseif正文解析正则表达式)

使用PCRE,我认为这个正则表达式递归应该处理嵌套的 if/elseif/else/endif构造。

在它的当前形式中,它是一个松散的解析,因为它没有定义
很好[if/elseif: body ]的形式 例如,[if:是起始分隔符构造,]是结尾吗? 并且应该发生错误等等。如果需要严格解析,可以这样做 现在它基本上使用[if: body ]作为开始分隔符
[endif]作为查找嵌套构造的结束分隔符。

此外,它将body松散地定义为[^\]]*,在严肃的解析中 情况,必须充实,以说明报价和东西 就像我说的那样,将它分开是可行的,但更多的是 参与其中。我在语言层面上做到了这一点,并不是一件轻而易举的事。

底部有一个宿主语言使用伪代码样本 语言递归演示了如何提取嵌套内容
正确。

正则表达式匹配核心的当前 outter shell。 核心的位置 是内部嵌套的内容。

每次对ParseCore()的调用都是在ParseCore()内部启动的 (来自 main()的初始调用除外。

由于范围界定似乎没有具体说明,我已经做出了可以看到的假设 评论中散落着。

if/elseif正文中有一个占位符 然后可以解析 (operations) 部分,这部分实际上是第2部分 我还没有完成这项练习 注意 - 我会尝试这样做,但我今天没有时间。

如果您有任何疑问,请与我们联系。

(?s)(?:(?<Content>(?&_content))|\[elseif:(?<ElseIf_Body>(?&_ifbody)?)\]|(?<Else>(?&_else))|(?<Begin>\[if:(?<If_Body>(?&_ifbody)?)\])(?<Core>(?&_core)|)(?<End>\[endif\])|(?<Error>(?&_keyword)))(?(DEFINE)(?<_ifbody>(?>[^\]])+)(?<_core>(?>(?<_content>(?>(?!(?&_keyword)).)+)|(?(<_else>)(?!))(?<_else>(?>\[else\]))|(?(<_else>)(?!))(?>\[elseif:(?&_ifbody)?\])|(?>\[if:(?&_ifbody)?\])(?:(?=.)(?&_core)|)\[endif\])+)(?<_keyword>(?>\[(?:(?:if|elseif):(?&_ifbody)?|endif|else)\])))

Formatted and tested:

 (?s)                               # Dot-all modifier

 # =====================
 # Outter Scope
 # ---------------

 (?:
      (?<Content>                        # (1), Non-keyword CONTENT
           (?&_content) 
      )
   |                                   # OR,
      # --------------
      \[ elseif:                         # ELSE IF
      (?<ElseIf_Body>                    # (2), else if body
           (?&_ifbody)? 
      )
      \]
   |                                   # OR
      # --------------
      (?<Else>                           # (3), ELSE
           (?&_else) 
      )
   |                                   # OR
      # --------------
      (?<Begin>                          # (4), IF
           \[ if: 
           (?<If_Body>                        # (5), if body
                (?&_ifbody)? 
           )
           \]
      )
      (?<Core>                           # (6), The CORE
           (?&_core) 
        |  
      )
      (?<End>                            # (7)
           \[ endif \]                        # END IF
      )
   |                                   # OR
      # --------------
      (?<Error>                          # (8), Unbalanced If, ElseIf, Else, or End
           (?&_keyword) 
      )
 )

 # =====================
 #  Subroutines
 # ---------------

 (?(DEFINE)

      # __ If Body ----------------------
      (?<_ifbody>                        # (9)
           (?> [^\]] )+
      )

      # __ Core -------------------------
      (?<_core>                          # (10)
           (?>
                #
                # __ Content ( non-keywords )
                (?<_content>                       # (11)
                     (?>
                          (?! (?&_keyword) )
                          . 
                     )+
                )
             |  
                #
                # __ Else
                # Guard:  Only 1 'else'
                # allowed in this core !!

                (?(<_else>)
                     (?!)
                )
                (?<_else>                          # (12)
                     (?> \[ else \] )
                )
             |  
                #
                # __ ElseIf
                # Guard:  Not Else before ElseIf
                # allowed in this core !!

                (?(<_else>)
                     (?!)
                )
                (?>
                     \[ elseif:
                     (?&_ifbody)? 
                     \]
                )
             |  
                #
                # IF  (block start)
                (?>
                     \[ if: 
                     (?&_ifbody)? 
                     \]
                )
                # Recurse core
                (?:
                     (?= . )
                     (?&_core) 
                  |  
                )
                # END IF  (block end)
                \[ endif \] 
           )+
      )

      # __ Keyword ----------------------
      (?<_keyword>                       # (13)
           (?>
                \[ 
                (?:
                     (?: if | elseif )
                     : (?&_ifbody)? 
                  |  endif
                  |  else
                )
                \]
           )
      )
 )

主机语言伪代码

 bool bStopOnError = false;
 regex RxCore("....."); // Above regex ..

 bool ParseCore( string sCore, int nLevel )
 {
     // Locals
     bool bFoundError = false;
     bool bBeforeElse = true;
     match _matcher;

     while ( search ( core, RxCore, _matcher ) )
     {
       // Content
         if ( _matcher["Content"].matched == true )
           // Print non-keyword content
           print ( _matcher["Content"].str() );

           // OR, Analyze content.
           // If this 'content' has error's and wish to return.
           // if ( bStopOnError )
           //   bFoundError = true;

         else

       // ElseIf
         if ( _matcher["ElseIf_Body"].matched == true )
         {
             // Check if we are not in a recursion
             if ( nLevel <= 0 )
             {
                // Report error, this 'elseif' is outside an 'if/endif' block
                // ( note - will only occur when nLevel == 0 )
                print ("\n>> Error, 'elseif' not in block, body = " + _matcher["ElseIf_Body"].str() + "\n";

                // If this 'else' error will stop the process.
                if ( bStopOnError == true )
                   bFoundError = true;
             }
             else
             {
                 // Here, we are inside a core recursion.
                 // That means we have not hit an 'else' yet
                 // because all elseif's precede it.
                 // Print 'elseif'.
                 print ( "ElseIf: " );

                 // TBD - Body regex below
                 // Analyze the 'elseif' body.
                 // This is where it's body is parsed.
                 // Use body parsing (operations) regex on it.
                 string sElIfBody = _matcher["ElseIf_Body"].str() );

                // If this 'elseif' body error will stop the process.
                if ( bStopOnError == true )
                   bFoundError = true;
             }
         }


       // Else
         if ( _matcher["Else"].matched == true )
         {
             // Check if we are not in a recursion
             if ( nLevel <= 0 )
             {
                // Report error, this 'else' is outside an 'if/endif' block
                // ( note - will only occur when nLevel == 0 )
                print ("\n>> Error, 'else' not in block\n";

                // If this 'else' error will stop the process.
                if ( bStopOnError == true )
                   bFoundError = true;
             }
             else
             {
                 // Here, we are inside a core recursion.
                 // That means there can only be 1 'else' within
                 // the relative scope of a single core.
                 // Print 'else'.
                 print ( _matcher["Else"].str() );

                 // Set the state of 'else'.
                 bBeforeElse == false;
             }
         }

         else

       // Error ( will only occur when nLevel == 0 )
         if ( _matcher["Error"].matched == true )
         {
             // Report error
             print ("\n>> Error, unbalanced " + _matcher["Error"].str() + "\n";
             // // If this unbalanced 'if/endif' error will stop the process.
             if ( bStopOnError == true )
                 bFoundError = true;
         }

         else

       // If/EndIf block
         if ( _matcher["Begin"].matched == true )
         {
             // Print 'If'
             print ( "If:" );

             // Analyze 'if body' for error and wish to return.

             // TBD - Body regex below.
             // Analyze the 'if' body.
             // This is where it's body is parsed.
             // Use body parsing (operations) regex on it.
             string sIfBody = _matcher["If_Body"].str() );

             // If this 'if' body error will stop the process.
              if ( bStopOnError == true )
                  bFoundError = true;
              else
              {

                  //////////////////////////////
                  // Recurse a new 'core'
                  bool bResult = ParseCore( _matcher["Core"].str(), nLevel+1 );
                  //////////////////////////////

                  // Check recursion result. See if we should unwind.
                  if ( bResult == false && bStopOnError == true )
                      bFoundError = true;
                  else
                      // Print 'end'
                      print ( "EndIf" );
              }
         }

         else
         {
            // Reserved placeholder, won't get here at this time.
         }

       // Error-Return Check
         if ( bFoundError == true && bStopOnError == true )
              return false;
     }

     // Finished this core!! Return true.
     return true;
 }

 ///////////////////////////////
 // Main

 string strInitial = "...";

 bool bResult = ParseCore( strInitial, 0 );
 if ( bResult == false )
    print ( "Parse terminated abnormally, check messages!\n" );

outter core 的输出样本匹配
请注意,当内核的匹配时,会有更多匹配。

 **  Grp 0               -  ( pos 0 , len 211 ) 
[if:(a+b-c/d*e)|(x-y)&!(z%3=0)]
    output
[elseif:('b'+'atman'='batman')]
    output2
[elseif:('b'+'atman'='batman')]
    output3
[elseif:('b'+'atman'='batman')]
    output4
[else]
    output5
[endif]  
 **  Grp 1 [Content]     -  NULL 
 **  Grp 2 [ElseIf_Body] -  NULL 
 **  Grp 3 [Else]        -  NULL 
 **  Grp 4 [Begin]       -  ( pos 0 , len 31 ) 
[if:(a+b-c/d*e)|(x-y)&!(z%3=0)]  
 **  Grp 5 [If_Body]     -  ( pos 4 , len 26 ) 
(a+b-c/d*e)|(x-y)&!(z%3=0)  
 **  Grp 6 [Core]        -  ( pos 31 , len 173 ) 

    output
[elseif:('b'+'atman'='batman')]
    output2
[elseif:('b'+'atman'='batman')]
    output3
[elseif:('b'+'atman'='batman')]
    output4
[else]
    output5

 **  Grp 7 [End]         -  ( pos 204 , len 7 ) 
[endif]  
 **  Grp 8 [Error]       -  NULL 
 **  Grp 9 [_ifbody]     -  NULL 
 **  Grp 10 [_core]       -  NULL 
 **  Grp 11 [_content]    -  NULL 
 **  Grp 12 [_else]       -  NULL 
 **  Grp 13 [_keyword]    -  NULL 

-----------------------------

 **  Grp 0               -  ( pos 211 , len 4 ) 



 **  Grp 1 [Content]     -  ( pos 211 , len 4 ) 



 **  Grp 2 [ElseIf_Body] -  NULL 
 **  Grp 3 [Else]        -  NULL 
 **  Grp 4 [Begin]       -  NULL 
 **  Grp 5 [If_Body]     -  NULL 
 **  Grp 6 [Core]        -  NULL 
 **  Grp 7 [End]         -  NULL 
 **  Grp 8 [Error]       -  NULL 
 **  Grp 9 [_ifbody]     -  NULL 
 **  Grp 10 [_core]       -  NULL 
 **  Grp 11 [_content]    -  NULL 
 **  Grp 12 [_else]       -  NULL 
 **  Grp 13 [_keyword]    -  NULL 

-----------------------------

 **  Grp 0               -  ( pos 215 , len 74 ) 
[if:(a+b-c/d*e)|(x-y)&!(z%3=0)]
    output6
[else]
    output7
[endif]  
 **  Grp 1 [Content]     -  NULL 
 **  Grp 2 [ElseIf_Body] -  NULL 
 **  Grp 3 [Else]        -  NULL 
 **  Grp 4 [Begin]       -  ( pos 215 , len 31 ) 
[if:(a+b-c/d*e)|(x-y)&!(z%3=0)]  
 **  Grp 5 [If_Body]     -  ( pos 219 , len 26 ) 
(a+b-c/d*e)|(x-y)&!(z%3=0)  
 **  Grp 6 [Core]        -  ( pos 246 , len 36 ) 

    output6
[else]
    output7

 **  Grp 7 [End]         -  ( pos 282 , len 7 ) 
[endif]  
 **  Grp 8 [Error]       -  NULL 
 **  Grp 9 [_ifbody]     -  NULL 
 **  Grp 10 [_core]       -  NULL 
 **  Grp 11 [_content]    -  NULL 
 **  Grp 12 [_else]       -  NULL 
 **  Grp 13 [_keyword]    -  NULL 

这是If / ElseIf Body 正则表达式

原始

(?|((?:\s*[^\^=<>+\-%/!&|()\[\]*\s]\s*)+)([\^+\-%/*=]+)(?=\s*[^\^=<>+\-%/!&|()\[\]*\s])|\G(?!^)(?<=[\^+\-%/*=])((?:\s*[^\^=<>+\-%/!&|()\[\]*\s]\s*)+)())

Stringed

'~(?|((?:\s*[^\^=<>+\-%/!&|()\[\]*\s]\s*)+)([\^+\-%/*=]+)(?=\s*[^\^=<>+\-%/!&|()\[\]*\s])|\G(?!^)(?<=[\^+\-%/*=])((?:\s*[^\^=<>+\-%/!&|()\[\]*\s]\s*)+)())~'

扩展

 (?|                                           # Branch Reset
      (                                             # (1 start), Operand
           (?: \s* [^\^=<>+\-%/!&|()\[\]*\s] \s* )+
      )                                             # (1 end)
      ( [\^+\-%/*=]+ )                              # (2), Forward Operator
      (?= \s* [^\^=<>+\-%/!&|()\[\]*\s] )
   |  
      \G 
      (?! ^ )
      (?<= [\^+\-%/*=] )
      (                                             # (1 start), Last Operand
           (?: \s* [^\^=<>+\-%/!&|()\[\]*\s] \s* )+
      )                                             # (1 end)
      ( )                                           # (2), Last-Empty Forward Operator
 )

这是如何运作的:
假设非常简单的结构 这只会解析数学运算符/运算符的内容 它不会解析任何封闭的括号块,也不会解析任何逻辑或数学 两者之间的运营商

如果需要,提前解析所有括号块,即\( [^)* \)
类似。或者拆分像|这样的逻辑运算符。

正文正则表达式使用分支重置来获取操作数/运算符序列 它总是匹配两件事 组1包含操作数,组2包含操作符。

如果组2为空,则组1是序列中的 last 操作数。

有效运算符为^ + - % / * = 包括等于=,因为它分隔了操作集合
并且可以被注意为分离。

关于这个身体正则表达式的结论是它非常简单和
仅适合简单使用。涉及更复杂的事情 这不是要走的路。

输入/输出样本1:

(a+b-c/d*e)

 **  Grp 1 -  ( pos 1 , len 1 ) 
a  
 **  Grp 2 -  ( pos 2 , len 1 ) 
+  
------------
 **  Grp 1 -  ( pos 3 , len 1 ) 
b  
 **  Grp 2 -  ( pos 4 , len 1 ) 
-  
------------
 **  Grp 1 -  ( pos 5 , len 1 ) 
c  
 **  Grp 2 -  ( pos 6 , len 1 ) 
/  
------------
 **  Grp 1 -  ( pos 7 , len 1 ) 
d  
 **  Grp 2 -  ( pos 8 , len 1 ) 
*  
------------
 **  Grp 1 -  ( pos 9 , len 1 ) 
e  
 **  Grp 2 -  ( pos 10 , len 0 )  EMPTY 

输入/输出样本2:

('b'+'atman'='batman')

 **  Grp 1 -  ( pos 1 , len 3 ) 
'b'  
 **  Grp 2 -  ( pos 4 , len 1 ) 
+  
------------
 **  Grp 1 -  ( pos 5 , len 7 ) 
'atman'  
 **  Grp 2 -  ( pos 12 , len 1 ) 
=  
------------
**  Grp 1 -  ( pos 13 , len 8 ) 
'batman'  
 **  Grp 2 -  ( pos 21 , len 0 )  EMPTY 

答案 1 :(得分:3)

你在这里有不同的可能性。

正则表达式版本

^\h*\[if.*\]\R                        # if in the first line
(?<if>(?:(?!\[elseif)[\s\S])+)\R      # output
^\h*\[elseif.*\]\R                    # elseif
(?<elseif>(?:(?!\[else)[\s\S])+)\R    # output
^\h*\[else.*\]\R                      # elseif
(?<else>(?:(?!\[endif)[\s\S])+)\R     # output
^\[endif\]

之后,您有三个已命名的已捕获组(ifelseifelse)。
a demo for this one on regex101.com

PHP中,这将是:

<?php
$code = <<<EOF
[if:(a+b-c/d*e)|(x-y)&!(z%3=0)]
output
[elseif:('b'+'atman'='batman')]
output2
out as well
[else]
output3
some other output here
[endif]
EOF;

$regex = '~
            ^\h*\[if.*\]\R                        # if in the first line
            (?<if>(?:(?!\[elseif)[\s\S])+)\R      # output
            ^\h*\[elseif.*\]\R                    # elseif
            (?<elseif>(?:(?!\[else)[\s\S])+)\R    # output
            ^\h*\[else.*\]\R                      # elseif
            (?<else>(?:(?!\[endif)[\s\S])+)\R     # output
            ^\[endif\]
          ~xm';

preg_match_all($regex, $code, $parts);
print_r($parts);
?>

<小时/>

编程逻辑

也许最好略读线条并寻找[if...],在字符串中捕获任何高达[elseif...]的内容,然后将它们粘合在一起。

<?php

$code = <<<EOF
[if:(a+b-c/d*e)|(x-y)&!(z%3=0)]
output
[elseif:('b'+'atman'='batman')]
output2
out as well
[else]
output3
some other output here
[endif]
EOF;

// functions, shamelessly copied from http://stackoverflow.com/questions/834303/startswith-and-endswith-functions-in-php
function startsWith($haystack, $needle) {
    // search backwards starting from haystack length characters from the end
    return $needle === "" || strrpos($haystack, $needle, -strlen($haystack)) !== false;
}

function endsWith($haystack, $needle) {
    // search forward starting from end minus needle length characters
    return $needle === "" || (($temp = strlen($haystack) - strlen($needle)) >= 0 && strpos($haystack, $needle, $temp) !== false);
}

$code = explode("\n", $code);
$buffer = array("if" => null, "elseif" => null, "else" => null);

$pointer = false;
for ($i=0;$i<count($code);$i++) {
	$save = true;
	if (startsWith($code[$i], "[if")) {$pointer = "if"; $save = false;}
	elseif (startsWith($code[$i], "[elseif")) {$pointer = "elseif"; $save = false; }
	elseif (startsWith($code[$i], "[else")) {$pointer = "else"; $save = false; }
	elseif (startsWith($code[$i], "[endif")) {$pointer = false; $save = false; }

	if ($pointer && $save) $buffer[$pointer] .= $code[$i] . "\n";

}
print_r($buffer);

?>