我正在以学习和爱好的名义开发自己的模板引擎。我有一个正则表达式,它使用与TWIG几乎相同的语法来查找if语句。
您可以在这里查看regex,其中包含一些工作示例,然后是我正在尝试使其工作的示例。
这是正则表达式:
{%'s*if's+(?<var>(?:[a-zA-Z_'x7f-'xff][a-zA-Z0-9_'x7f-'xff]*)(?:'.(?:[a-zA-Z0-9_'x7f-'xff]*))*)'s(?:(?<operation>=|!=|<=|<|>=|>)'s(?<var2>(?:(?:(?1)*)(?:'.(?:(?2)*))*)|(?:[0-9]+))'s?)?%}(?<if>(?:(?!{% e(?:lse|nd if) %}).)*)(?:{%'h?else'h?%}(?<else>['s'S]*?))?{%'h?end if's?%}
这是它正在处理的数据:
THESE WORK
{% if thing %}
stuff
{% end if %}
{% if thing %}
stuff
{% else %}
other stuff
{% end if %}
{%if thing = thingy %}
stuff
{% else %}
other stuff
{% end if %}
THIS DOESN'T
Problem starts here:
{% if this = that %}
{% if item.currency = 0 %}
selected="selected"
{% else %}
you
{% end if %}
{% end if %}
基本上,我希望正则表达式搜索最后一个{%end if%}标记,并将其间的所有内容用作字符串,以便稍后递归解析。
此外,作为附带说明,将问题的大部分信息保留在regex-tester的链接中是否合适?或者我应该把问题的大部分也复制到这里(SO上)吗?
修订版1
既然你是在试验,经过一段时间的闲逛,我为你想出了一个通用的正则表达式。
这可能会增加你目前的知识,并提供一些可以借鉴的东西
剧情简介:
在纯正则表达式解决方案中,平衡文本的概念远至
正则表达式引擎已经失效。它不会填补细节
为此,你必须自己做。
与下降语法分析器或类似语法分析器相比,这是一种缓慢的方法
不同的是,它不需要放松就能知道自己在哪里。
因此,这将允许您在遇到错误时继续进行解析
从过去的错误中获得更多的意义,以帮助调试。
在做这种事情时,您应该解析每一个字符
因此,我们解析内容、分隔符开始、核心、结束和错误。
在这种情况下,我们在外部范围上留出了7个捕获组来浏览信息。
Content
-它由if/else/end if
以外的任何内容组成。
Else
-这是else
语句
Begin
-这是if
块的开始
If_Content
-这是if block content
Core
-这是all between
外部开始和结束。还包含嵌套内容。
End
-这是外部end if
块
Error
-这是不平衡误差,它是if
或end if
。
用法:
在主机程序中,定义一个名为ParseCore()
的函数此函数需要传递(或知道)当前核心字符串
如果它是c++,它将被传递开始和结束字符串迭代器
无论如何,字符串必须是函数的本地字符串。
在这个函数中,在while循环中解析字符串
在每一场比赛中,做一个if/else,看看上面的哪一组匹配
只能是这些组合
Content
或Else
或Begin, If_Content, Core, End
或Error
只有一组对递归很重要。这就是Core
组
当该组匹配时,您对
进行递归函数调用ParseCore()
将Core字符串传递给它。
重复此操作,直到不再匹配为止
错误报告、创建结构树以及其他任何操作都可以完成
在该功能内
您甚至可以在任何时候设置一个全局标志来解除递归调用
然后退出。例如,如果出现错误或类似情况,您希望停止。
注意:在对ParseCore()
的初始调用中,只需传入整个原始字符串即可开始解析
祝你好运!
扩展
# (?s)(?:(?<Content>(?&_content))|(?<Else>(?&_else))|(?<Begin>{%'s*if's+(?<If_Content>(?&_ifbody))'s*%})(?<Core>(?&_core)|)(?<End>{%'s*end's+if's*%})|(?<Error>(?&_keyword)))(?(DEFINE)(?<_ifbody>(?>(?!%}).)+)(?<_core>(?>(?<_content>(?>(?!(?&_keyword)).)+)|(?(<_else>)(?!))(?<_else>(?>{%'s*else's*%}))|(?>{%'s*if's+(?&_ifbody)'s*%})(?:(?=.)(?&_core)|){%'s*end's+if's*%})+)(?<_keyword>(?>{%'s*(?:if's+(?&_ifbody)|end's+if|else)'s*%})))
(?s) # Dot-all modifier
# =====================
# Outter Scope
# ---------------
(?:
(?<Content> # (1), Non-keyword CONTENT
(?&_content)
)
| # OR,
# --------------
(?<Else> # (2), ELSE
(?&_else)
)
| # OR
# --------------
(?<Begin> # (3), IF
{% 's* if 's+
(?<If_Content> # (4), if content
(?&_ifbody)
)
's* %}
)
(?<Core> # (5), The CORE
(?&_core)
|
)
(?<End> # (6)
{% 's* end 's+ if 's* %} # END IF
)
| # OR
# --------------
(?<Error> # (7), Unbalanced IF or END IF
(?&_keyword)
)
)
# =====================
# Subroutines
# ---------------
(?(DEFINE)
# __ If Body ----------------------
(?<_ifbody> # (8)
(?>
(?! %} )
.
)+
)
# __ Core -------------------------
(?<_core> # (9)
(?>
#
# __ Content ( non-keywords )
(?<_content> # (10)
(?>
(?! (?&_keyword) )
.
)+
)
|
#
# __ Else
# Guard: Only 1 'else'
# allowed in this core !!
(?(<_else>)
(?!)
)
(?<_else> # (11)
(?> {% 's* else 's* %} )
)
|
#
# IF (block start)
(?>
{% 's* if 's+
(?&_ifbody)
's* %}
)
# Recurse core
(?:
(?= . )
(?&_core)
|
)
# END IF (block end)
{% 's* end 's+ if 's* %}
)+
)
# __ Keyword ----------------------
(?<_keyword> # (12)
(?>
{% 's*
(?:
if 's+ (?&_ifbody)
| end 's+ if
| else
)
's* %}
)
)
)
示例输入(已删除)
选定输出(已删除)
伪代码使用示例
bool bStopOnError = false;
regex RxCore(".....");
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
// 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/end if' block
// ( note - will only occur when nLevel == 0 )
print ("'n>> Error, 'else' not in block " + _matcher["Else"].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 there can only be 1 'else'.
// 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/end if' error will stop the process.
if ( bStopOnError == true )
bFoundError = true;
}
else
// IF/END IF block
if ( _matcher["Begin"].matched == true )
{
// Analyze 'if content' for error and wish to return.
string sIfContent = _matcher["If_Content"].str();
// if ( bStopOnError )
// bFoundError = true;
// else
// {
// Print 'begin' ( includes 'if content' )
print ( _matcher["Begin"].str() );
//////////////////////////////
// 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 ( _matcher["End"].str() );
// }
}
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" );