正则expression式来检测分号结尾的C ++ for&while循环

在我的Python应用程序中,我需要编写一个正则expression式,它与用分号( ; )终止的C ++ forwhile循环匹配。 例如,它应该匹配这个:

 for (int i = 0; i < 10; i++); 

…但不是这样:

 for (int i = 0; i < 10; i++) 

乍看起来,这看起来微不足道,直到您意识到开始和结束括号之间的文本可能包含其他括号,例如:

 for (int i = funcA(); i < funcB(); i++); 

我正在使用python.re模块。 现在我的正则expression式看起来像这样(我留下了我的意见,所以你可以更容易理解):

 # match any line that begins with a "for" or "while" statement: ^\s*(for|while)\s* \( # match the initial opening parenthesis # Now make a named group 'balanced' which matches a balanced substring. (?P<balanced> # A balanced substring is either something that is not a parenthesis: [^()] | # …or a parenthesised string: \( # A parenthesised string begins with an opening parenthesis (?P=balanced)* # …followed by a sequence of balanced substrings \) # …and ends with a closing parenthesis )* # Look for a sequence of balanced substrings \) # Finally, the outer closing parenthesis. # must end with a semi-colon to match: \s*;\s* 

这对所有上述情况都是完美的,但只要尝试使for循环的第三部分包含一个函数就会中断,如下所示:

 for (int i = 0; i < 10; doSomethingTo(i)); 

我认为这会中断,因为只要在开始和结束括号之间插入一些文本,“平衡”组就匹配包含文本的组,因此(?P=balanced)部分不再起作用,因为它不会匹配(由于括号内的文字不同)。

在我的Python代码中,我使用VERBOSE和MULTILINE标志,并创build正则expression式,如下所示:

 REGEX_STR = r"""# match any line that begins with a "for" or "while" statement: ^\s*(for|while)\s* \( # match the initial opening parenthesis # Now make a named group 'balanced' which matches # a balanced substring. (?P<balanced> # A balanced substring is either something that is not a parenthesis: [^()] | # …or a parenthesised string: \( # A parenthesised string begins with an opening parenthesis (?P=balanced)* # …followed by a sequence of balanced substrings \) # …and ends with a closing parenthesis )* # Look for a sequence of balanced substrings \) # Finally, the outer closing parenthesis. # must end with a semi-colon to match: \s*;\s*""" REGEX_OBJ = re.compile(REGEX_STR, re.MULTILINE| re.VERBOSE) 

任何人都可以提出这个正则expression式的改进? 我的脑袋变得越来越复杂了。

你可以编写一个非常简单的例程,而不需要使用正则expression式:

  • 设置一个位置计数器的位置,以便在你的for或之后指向前面的括号。
  • 将一个开放的括号计数器openBr0
  • 现在继续增加pos ,读取各个位置的字符,当看到一个openBr时增加openBr当你看到一个openBr时递减。 这将在开始时递增一次,对于“ for ( ”中的第一个开始括号, for (其间的一些括号增加和减less一些括号,当括号closures时将其重新设置为0
  • 所以,当openBr再次为0时停止。

停止位置是for(...)右括号。 现在你可以检查是否有分号符号。

这是你不应该用正则expression式来做的事情。 只需一次parsingstring一个字符,跟踪开/关括号。

如果这就是你正在寻找的东西,那么你绝对不需要一个完整的C ++语法词法分析器/parsing器。 如果你想练习,你可以写一个recursion的小parsing器,但即使这样匹配的圆括号也是如此。

这是使用错误工具进行工作的一个很好的例子。 正则expression式不能很好地处理任意嵌套的子匹配。 你应该做的是使用一个真正的词法分析器和parsing器(C ++的语法应该很容易find),并查找意外的空循环体。

我甚至不会注意那些人的内容。

只要匹配任何以for开头, for分号结束的行:

 ^\t*for.+;$ 

除非你有多条语句拆分语句,那么这样可以正常工作吗?

试试这个正则expression式

 ^\s*(for|while)\s* \( (?P<balanced> [^()]* | (?P=balanced) \) \s*;\s 

我删除了围绕(?P=balanced)的环绕\( \) ,并将*移到任何不平行的序列后面。 我已经有了这个工作,以提高xpressive,并重新检查该网站( Xpressive ),以刷新我的记忆。

格雷格绝对正确。 这种parsing不能用正则expression式来完成。 我认为有可能build立一些可怕的怪物,可以在很多情况下工作,但是你会碰到一些事情。

你真的需要使用更传统的parsing技术。 例如,写一个recursion的正确的parsing器来完成你所需要的工作非常简单。

我不知道正则expression式能够很好地处理这样的事情。 尝试这样的事情

 line = line.Trim(); if(line.StartsWith("for") && line.EndsWith(";")){ //your code here } 

另一个想法忽略括号,并把它当作一个持有三个以分号分隔的值的构造:

 for\s*\([^;]+;[^;]+;[^;]+\)\s*; 

这个选项即使在分割多行(一次启用MULTILINE)的情况下也能工作,但是假定for ( ... ; ... ; ... )是唯一有效的构造,所以不能用for ( x in y )构造,或其他偏差。

还假设没有包含分号的函数作为参数,例如:

 for ( var i = 0; i < ListLen('a;b;c',';') ; i++ ); 

这是否是一个可能的情况取决于你实际上在做什么。

不是一个Python解决scheme(也许你可以写一个包装…)

首先,下载lexertl( http:/www.benhanson.net/lexertl.html ),然后:

 #include <algorithm> #include "lexertl/generator.hpp" #include <iostream> #include "lexertl/lookup.hpp" int main() { lexertl::rules rules_; lexertl::state_machine sm_; rules_.add_state("FW"); rules_.add_state("SEMI"); rules_.add_state("NESTED"); rules_.add("*", "[/][/].*|[/][*](.|\n)*?[*][/]|[\"](.|\\\")*[\"]", rules_.skip(), "."); rules_.add("INITIAL", "for\\s*\\([^;]*;[^;]*;|while\\s*\\(", rules_.skip(), "FW"); rules_.add("FW", "\\)", rules_.skip(), "SEMI"); rules_.add("FW,NESTED", "\\(", ">NESTED"); rules_.add("NESTED", "\\)", rules_.skip(), "<"); rules_.add("SEMI", "\\s*;", 1, "INITIAL"); rules_.add("SEMI", ".|\n", rules_.skip(), "INITIAL"); lexertl::generator::build (rules_, sm_); lexertl::memory_file buff_("main.cpp"); const char *start_ = buff_.data (); const char *end_ = start_ + buff_.size (); lexertl::crmatch results_(start_, end_); do { lexertl::lookup(sm_, results_); if (results_.id == 1) { std::cout << "found on line " << std::count(start_, results_.end, '\n') + 1 << '\n'; } } while (results_.id != sm_.eoi()); return 0; } 

正如弗兰克所说,这是最好的没有正则expression式。 这是(一个丑陋的)单行:

 match_string = orig_string[orig_string.index("("):len(orig_string)-orig_string[::-1].index(")")] 

匹配他评论中提到的巨魔线est:

 orig_string = "for (int i = 0; i < 10; doSomethingTo(\"(\"));" match_string = orig_string[orig_string.index("("):len(orig_string)-orig_string[::-1].index(")")] 

返回(int i = 0; i < 10; doSomethingTo("("))

这是通过向前穿过弦,直到它到达第一个开放paren,然后向后,直到它到达第一个closuresparen。 然后使用这两个索引来分割string。