TCL:正则表达式,用于查找字符串中的while

时间:2012-11-01 09:42:25

标签: regex tcl

我正在尝试编写一个正则表达式来搜索从C ++源代码文件中读取的字符串中的/ if / while关键字,但不包括任何包含它们的单词:

WhatifYes()
Whatfor()
Waitforwhile()

我写了下面的正则表达式:

if { [ regexp {(for|while|if)(\s+)(\()} $lineValue ] } { 

但它并没有像以下那样收集案件:

while(( int x = 0 ) > 0 );
while(( int x = 0 ) > 0 )
for(int y =0 ; ; )
for(int y =0 ; ; );
if( (int x = 9) > 0 )
if( (int x = 9) > 0 );

最初我认为因为我的正则表达式被定义为:

if/for/while \s+ ( #space or multiple spaces

但我尝试在上面的示例中包含空格:

while (( int x = 0 ) > 0 );
while (( int x = 0 ) > 0 )
if ( (int x = 9) > 0 )
if ( (int x = 9) > 0 );

仍然正在使用正则表达式 - 请让我知道我应该使用什么正则表达式捕获它们?

2 个答案:

答案 0 :(得分:4)

您的部分问题很容易解决,部分内容非常困难。

简单的部分是确保你有一个完整的词:\m约束转义只在一个单词的开头匹配,而\M约束转义匹配在结尾,所以我们可以使用:

# Nothing capturing; you can add that as necessary
# Ellipsis for the bits I've not talked about yet
regexp {\m(?:while|if|for)\M\s*...} ...

非常困难的部分是在括号中匹配部分。问题在于,这实际上是一种“语言”(在理论意义上),需要一种不同于正则表达式的解析器才能匹配(即递归下降解析器,其具有比使用的有限自动机更复杂的状态模型。 RE匹配)。更重要的是,在这些表达式中使用()个字符很常见。最简单的方法是匹配在行尾的紧密括号,可能后面跟一个分号,但这绝对不正确。或者,也可以支持有限数量的嵌套parens。

# Match a few levels...
regexp {\m(?:while|if|for)\M\s*\((?:[^()]|\((?:[^()]|\([^()]*\))*\))*\)} ...

所以,让我们打破RE:

\m                                Word start
(?:while|if|for)                  One of the keywords 
\M                                Word end
\s*                               Optional spaces
\(                                Open paren
  (?:                             Either...
    [^()]                           Non-paren...
  |                               Or...
    \(                              Open paren
      (?:                           Either...
        [^()]                         Non-paren...
      |                             Or...
        \(                            Open paren
          [^()]*                      Non-parens
        \)                            Close paren
      )*                            ... as many of the above as needed
    \)                              Close paren
  )*                              ... as many of the above as needed
\)                                Close paren

如果你看一下上面的内容,你会发现一个模式。是的,你可以继续筑巢,做到你想要的深度。 无法做的是让RE引擎为你做嵌套。

答案 1 :(得分:0)

在你的正则表达式中,你正在使用\ s +。这意味着必须至少有一个空格/制表符/换行符。使用\ s *(0或更多空格)并为之前的内容添加逻辑:

if { [ regexp {(^|[ \t])(for|while|if)(\s*)(\()} $lineValue ] } {