我正在设计脚本并尝试在 php 中不使用 eval 构建 if 结构。
仍然不完整,但正在突破,它是为了做一个模板引擎,引擎的“if”部分。不允许赋值运算符,但我需要测试值不允许 php 代码注入(inject),准确地说不使用 eval 它需要在变量之间进行单独的操作以防止注入(inject)攻击。
正则表达式必须捕获
[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 block 以及条件语句:
$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 = '~([^\^=<>+\-%/!&|()*]+)([\^+\-%/!|&*])([^\^=<>+\-%/!&|()*]*)~';
然而,它只会将它们配对,缺少每个第 3 个运算符......
感谢您的帮助。
最佳答案
(编辑在底部添加了一个简单的if/elseif主体解析正则表达式)
使用 PCRE,我认为这个正则表达式递归应该处理嵌套
if/elseif/else/endif 构造。
在当前形式下,它是一个松散解析,因为它没有定义
[if/elseif: body ] 的形式非常好。
例如,[if: 是开始的定界符结构而 ] 是结束的吗?
如果发生错误等。如果需要严格解析,可以通过这种方式完成。
现在它基本上是使用 [if: body ] 作为开始分隔符
和 [endif] 作为查找嵌套结构的结束定界符。
此外,它松散地将 body 定义为 [^\]]*,在认真的解析中
情况,必须充实以说明报价和其他内容。
就像我说的那样,将它拆开是可行的,但远不止于此
涉及。我已经在语言层面上做到了这一点,这并不简单。
底部有宿主语言使用伪代码示例。
语言递归演示了如何提取嵌套内容
正确。
正则表达式匹配核心的当前外壳。 核心
是内部嵌套内容。
对 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)\])))
(?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
)
这是它的运作方式:
假定构造非常简单。
这只会解析数学操作数/运算符。
它不会解析任何封闭的括号 block ,也不会解析任何逻辑或数学
之间的运营商。
如果需要,提前解析任何括号 block ,即 \( [^)*\) 或
相似的。或者拆分逻辑运算符,如 |。
主体正则表达式使用分支重置来获取操作数/运算符序列。
它总是匹配两个东西。
第 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
关于php - 正则表达式 - 获取元素以呈现 if 语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37772338/
在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg
有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url
我有一个存储主机名的Ruby数组server_names。如果我打印出来,它看起来像这样:["hostname.abc.com","hostname2.abc.com","hostname3.abc.com"]相当标准。我想要做的是获取这些服务器的IP(可能将它们存储在另一个变量中)。看起来IPSocket类可以做到这一点,但我不确定如何使用IPSocket类遍历它。如果它只是尝试像这样打印出IP:server_names.eachdo|name|IPSocket::getaddress(name)pnameend它提示我没有提供服务器名称。这是语法问题还是我没有正确使用类?输出:ge
我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c
我正在检查一个Rails项目。在ERubyHTML模板页面上,我看到了这样几行:我不明白为什么不这样写:在这种情况下,||=和ifnil?有什么区别? 最佳答案 在这种特殊情况下没有区别,但可能是出于习惯。每当我看到nil?被使用时,它几乎总是使用不当。在Ruby中,很少有东西在逻辑上是假的,只有文字false和nil是。这意味着像if(!x.nil?)这样的代码几乎总是更好地表示为if(x)除非期望x可能是文字false。我会将其切换为||=false,因为它具有相同的结果,但这在很大程度上取决于偏好。唯一的缺点是赋值会在每次运行
我安装了ruby版本管理器,并将RVM安装的ruby实现设置为默认值,这样'哪个ruby'显示'~/.rvm/ruby-1.8.6-p383/bin/ruby'但是当我在emacs中打开inf-ruby缓冲区时,它使用安装在/usr/bin中的ruby。有没有办法让emacs像shell一样尊重ruby的路径?谢谢! 最佳答案 我创建了一个emacs扩展来将rvm集成到emacs中。如果您有兴趣,可以在这里获取:http://github.com/senny/rvm.el
假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit
假设我在Ruby中有这个each循环。@list.each{|i|putsiifi>10breakend}我想循环遍历列表直到满足条件。这让我感到“不像Ruby”,因为我是Ruby的新手,是否有Ruby方法可以做到这一点? 最佳答案 您可以使用Enumerable#detect或Enumerable#take_while,取决于您想要的结果。@list.detect{|i|putsii>10}#Returnsthefirstelementgreaterthan10,ornil.正如其他人所指出的,更好的风格是先进行子选择,然后再对其
我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur
我注意到类定义,如果我打开classMyClass,并在不覆盖的情况下添加一些东西我仍然得到了之前定义的原始方法。添加的新语句扩充了现有语句。但是对于方法定义,我仍然想要与类定义相同的行为,但是当我打开defmy_method时似乎,def中的现有语句和end被覆盖了,我需要重写一遍。那么有什么方法可以使方法定义的行为与定义相同,类似于super,但不一定是子类? 最佳答案 我想您正在寻找alias_method:classAalias_method:old_func,:funcdeffuncold_func#similartoca