我正在以学习和爱好的名义研发我自己的模板引擎。我有一个正则表达式,它使用与TWIG几乎相同的语法来查找if语句。
您可以使用一些工作示例查看正则表达式here,然后查看正在尝试工作的示例。
这是正则表达式:
{%\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%}标记,并将其中的所有内容用作我之后可以递归解析的字符串。
另外,作为附注,将大部分问题的信息留在正则表达式测试人员的链接中是否合适?或者我是否也应该在这里复制大部分问题(在SO上)?
答案 0 :(得分:2)
第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" );