2010-04-14 95 views
4

我終於學習了正則表達式並使用ack進行了培訓。我相信這使用Perl正則表達式。爲什麼我用ack正則表達式得到額外的意外結果?

我想匹配其中第一個非空白字符爲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問題,很抱歉讓你爲此煩惱。

+0

作爲mobrule他回答說,你的正則表達式看起來不錯的你所描述的期望的行爲。你能編輯你的問題來包含示例數據,你使用的ack命令行和你想要的輸出嗎? – 2010-04-14 16:58:07

+0

如果你還沒有,請閱讀perlrequick(man perlrequick,perldoc perlrequick或在線查找)。之後,如果您想要更高級的功能,請閱讀perlre。無論如何,我強烈推薦O'Reilly的Mastering Regular Expressions。 – kbenson 2010-04-14 17:06:35

回答

4

ackgrep中,*匹配零個或多個,而不是零個或一個。所以我認爲你已經有了正確的解決方案。什麼樣的測試用例不會給你想要的結果?

# 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 
+0

@mobrule - ack主頁和OP問題均表明ack使用Perl正則表達式,而不是grep變體。 – DVK 2010-04-14 15:57:54

+0

'} else if(y!= 0){'在我的結果中。請注意,我在命令行表達式中使用單引號,是否可能與我的問題有關? – Gauthier 2010-04-15 07:25:13

6
^\s*if\s*\(\S+\s*! 
  • 使用\S非空白。 \w將不匹配任何特殊字符,因此if ($word將不匹配。可能是與您的規格確定,在這種情況下\w(字母加 「_」 )是OK
 
$ perl5.8 -e '{$s="else if (asdf \!= 1)"; if ($s =~ /^\s*if\s*\((\S+)\s*\!/) { print "|$1|\n";} else { print "NO MATCH\n";}}' 
NO MATCH 
$ perl5.8 -e '{$s="// if (asdf \!= 0)"; if ($s =~ /^\s*if\s*\((\S+)\s*\!/) { print "|$1|\n";} else { print "NO MATCH\n";}}' 
NO MATCH 
$ 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| 
+0

請忽略「!」前面的反斜線在我的例子中 - 這是爲了Unix shell的好處。在Perl內部,它只是「!」 – DVK 2010-04-14 15:39:15

+0

同樣在這裏。它看起來像'^'不起作用! – Gauthier 2010-04-15 07:26:48

+0

是的,我有ack.bat的地方,似乎刪除'^'字符! (見我編輯的文章)。 – Gauthier 2010-04-15 07:47:46

1

你可以試試:

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

\t*| * 

將零個或多個選項卡或零個或多個空格不混合的空格和選項卡。