4

我终于开始学习正则表达式并使用ack进行培训。我相信这使用 Perl 正则表达式。

我想匹配第一个非空白字符所在的所有行,if (<word> !元素之间有任意数量的空格。

这就是我想出的:

^[ \t]*if *\(\w+ *!

它几乎起作用了。^[ \t]*是错误的,因为它匹配一个或不匹配 [空格或制表符]。我想要的是匹配任何可能只包含空格或制表符(或什么都不包含)的东西。

例如,这些不应该匹配:

// if (asdf != 0)
else if (asdf != 1)

我该如何修改我的正则表达式?


编辑添加命令行

ack -i --group -a '^\s*if *\(\w+ *!' c:/work/proj/proj 

注意单引号,我不再那么确定它们了。

我的搜索库是一个更大的代码库。它确实包括匹配的表达式(相当多),但即使是例如:

274:                }else if (y != 0) 

,这是我通过上述命令得到的。


编辑添加 mobrule 的测试结果

Mobrule,感谢您为我提供了要测试的文本。我将在这里复制我收到的提示信息:

C:\Temp\regex>more ack.test
# ack.test
if (asdf != 0)    # no spaces - ok
 if (asdf != 0)   # single space - ok
    if (asdf != 0) # single tab - ok
   if (asdf != 0) # multiple space - ok
        if (asdf != 0) # multiple tab - ok
    if (asdf != 0) # spaces + tab ok
     if (asdf != 0) # tab + space ok
     if (asdf != 0) # space + tab + space ok
// if (asdf != 0)  # not ok
} else if (asdf != 0) # not ok

C:\Temp\regex>ack '^[ \t]*if *\(\w+ *!' ack.test

C:\Temp\regex>"C:\Program\git\bin\perl.exe" C:\bat\ack.pl '[ \t]*if *\(\w+ *!' a
ck.test
if (asdf != 0)    # no spaces - ok
 if (asdf != 0)   # single space - ok
    if (asdf != 0) # single tab - ok
   if (asdf != 0) # multiple space - ok
        if (asdf != 0) # multiple tab - ok
    if (asdf != 0) # spaces + tab ok
     if (asdf != 0) # tab + space ok
     if (asdf != 0) # space + tab + space ok
// if (asdf != 0)  # not ok
} else if (asdf != 0) # not ok

问题出在我对我的 ack.bat 的调用中!

ack.bat 包含:

"C:\Program\git\bin\perl.exe" C:\bat\ack.pl %*

虽然我用插入符号调用,但它会在调用 bat 文件时消失!

转义插入符号^^不起作用。

" "用而不是引用正则表达式' '。我的问题是 DOS/win 问题,很抱歉打扰大家。

4

3 回答 3

6
^\s*if\s*\(\S+\s*!
  • 用于\S非空白。\w不会匹配任何特殊字符,所以if ($word不会匹配。您的规格可能没问题,在这种情况下\w(字母数字加“_”)是可以的
$ perl5.8 -e '{$s="else if (asdf \!= 1)"; if ($s =~ /^\s*if\s*\((\S+)\s*\!/) { print "|$1|\n";} else { print "NO MATCH\n";} }'
不匹配
$ perl5.8 -e '{$s="// if (asdf \!= 0)"; if ($s =~ /^\s*if\s*\((\S+)\s*\!/) { print "|$1|\n";} else { print "NO MATCH\n";} }'
不匹配
$ perl5.8 -e '{$s=" if (asdf \!= 0)"; if ($s =~ /^\s*if\s*\((\S+)\s*\!/) { print "|$1|\n";} else { print "NO MATCH\n";} }'  
|asdf|
$ perl5.8 -e '{$s="if (asdf \!= 0)"; if ($s =~ /^\s*if\s*\((\S+)\s*\!/) { print "|$1|\n";} else { print "NO MATCH\n";} }'
|asdf|
$ perl5.8 -e '{$s="if (\$asdf \!= 0)"; if ($s =~ /^\s*if\s*\((\S+)\s*\!/) { print "|$1|\n";} else { print "NO MATCH\n";} }'
|$asdf|
于 2010-04-14T15:25:47.037 回答
4

ackandgrep中,*匹配零个或多个,而不是零个或一个。所以我认为你已经有了正确的解决方案。哪些测试用例没有给你想要的结果?

# ack.test
if (asdf != 0)    # no spaces - ok
 if (asdf != 0)   # single space - ok
    if (asdf != 0) # single tab - ok
   if (asdf != 0) # multiple space - ok
        if (asdf != 0) # multiple tab - ok
    if (asdf != 0) # spaces + tab ok
     if (asdf != 0) # tab + space ok
     if (asdf != 0) # space + tab + space ok
// if (asdf != 0)  # not ok
} else if (asdf != 0) # not ok

结果:

$ ack '^[ \t]*if *\(\w+ *!' ack.test
if (asdf != 0)    # no spaces - ok
 if (asdf != 0)   # single space - ok
        if (asdf != 0) # single tab - ok
   if (asdf != 0) # multiple space - ok
                if (asdf != 0) # multiple tab - ok
        if (asdf != 0) # spaces + tab ok
         if (asdf != 0) # tab + space ok
         if (asdf != 0) # space + tab + space ok

$ ack -v '^[ \t]*if *\(\w+ *!' ack.test
// if (asdf != 0)  # not ok
} else if (asdf != 0) # not ok
于 2010-04-14T15:43:02.413 回答
1

你可以试试:

(?:\t*| *)if *\(\w+ *!

.

\t*| *

将是零个或多个制表符或零个或多个空格,而不是空格和制表符的混合。

于 2010-04-14T15:28:50.797 回答