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

Posted

技术标签:

【中文标题】正则表达式 - 获取元素以呈现 if 语句【英文标题】:Regex - get elements to render if statement 【发布时间】:2016-10-12 20:15:32 【问题描述】:

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

仍然不完整,但通过,它是做一个模板引擎,引擎的“if”部分。不允许赋值运算符,但我需要测试值 不允许 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 和 else。

然后使用条件语句,我可以得到操作:

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

但是,它只会将它们配对,缺少每个第三个运算符...

感谢您的帮助。

【问题讨论】:

这个构造 [\S \t]+ 匹配除 [\r\n\f] 之外的任何字符,如果要匹配的块超过 1 个(贪婪),您的 [\s\S]+ 将不会停止计算。请提供更好的输入/预期输出样本。你可以试试(?s)(\[if:([^\]]+))\](.*?)\[endif\] 请看赏金cmets PCRE 正则表达式很容易放在一起,甚至是复杂的递归。问题源于从代码中判断意图。如果你认为你知道你需要什么,只需用简单的伪代码用英语说出来,而不需要宿主语言代码的详细信息。它必须是分开的。正则表达式本身就是一种语言。一心一意。还有一件事,使用和执行正则表达式递归还需要递归使用宿主语言。 我对使用托管语言的代码很好,如果看起来不是这样,请原谅我,我的意思是我不想要 eval 或 php 注入,因此测试代码的每个部分。 是的,看起来您正在尝试获取运算符,并且它直接围绕非运算符/父/等于字符。所以基本上,所有那些 相似 正则表达式和代码都可以使用这个~([^\^=&lt;&gt;+\-%/!&amp;|()*]+)([\^+\-%/!|&amp;*])([^\^=&lt;&gt;+\-%/!&amp;|()*]*)~ 压缩成一个 preg_match_all()。其中捕获组 2 包含运算符,您可以使用 if-then-else 逻辑对其进行测试。我希望我能提供进一步的帮助,但我不太明白你在做什么。 【参考方案1】:

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

正则表达式版本

^\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://***.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);

?>

【讨论】:

谢谢,这太棒了,但这是成功的一半,需要正则表达式来获取运算符/值/变量,将它们分开并执行 PEDMAS 并执行测试,我要求相当多,您为此付出了努力,----0---如果您给我完整的答案,则加分:):编辑,无法提高赏金:( 它是否考虑了递归? (在 if 中可以有 if 吗?) PEDMAS 是什么意思? PEMDAS,抱歉:括号、指数、乘除法、加减法、运算优先级。 获取所有值(字符串或数字)/变量/运算符的数组,并通过测试条件解析。 (对于变量,它们是我模板的一部分,不用管它们,只测试值,例如:[if:c=c] 为真 [if:1=1] 为真 [if:1.5+2.5=8 /2] 为真 [if:'string1' = 'string1'] 为真 [if:'string1' != 'string1']【参考方案2】:

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

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

在目前的形式中,它是一个松散的解析,因为它没有定义 很好[if/elseif: body ]的形式。 例如,[if: 是开始分隔符构造,] 是结尾吗? 如果发生错误等。如果需要 strict 解析,可以这样做。 现在它基本上是使用[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" );

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

 **  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*)+)())

弦乐

'~(?|((?:\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 组是序列中的最后一个操作数。

有效的运算符是^ + - % / * =。 包含等于 = 是因为它分隔了操作集群 并且可以被视为一种分离。

关于这个正文正则表达式的结论是它非常简单并且 只适合简单的使用。涉及任何更复杂的事情 这不会是要走的路。

输入/输出样本 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 

【讨论】:

以上是关于正则表达式 - 获取元素以呈现 if 语句的主要内容,如果未能解决你的问题,请参考以下文章

javascript - 将字符串与正则表达式数组匹配

Bash if 语句中的正则表达式匹配

正则表达式—简单验证

Nginx中if语句中的判断条件

我怎样才能简单地使用这种数字格式验证正则表达式?

使用正则表达式语句在休眠中使用 createSQLQuery 获取计数(*)