代码之家  ›  专栏  ›  技术社区  ›  Gauthier

为什么我的ack regex会得到额外的意外结果?

  •  4
  • Gauthier  · 技术社区  · 14 年前

    我终于学会了regexp和训练 ack . 我相信这使用perl regexp。

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

    这就是我想到的:

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

    只差一点就成功了。 ^[ \t]* 是错误的,因为它匹配一个或没有[空格或制表符]。 我想要的是匹配任何可能只包含空格或制表符(或不包含任何内容)的内容。

    例如,这些不应匹配:

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

    如何修改regexp?


    编辑 添加命令行

    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文件的调用中消失了!

    逃离插入符号 ^^ 不起作用。

    引用regex " " 而不是 ' ' 作品。我的问题是一个dos/win的问题,很抱歉打扰了你们。

    3 回复  |  直到 14 年前
        1
  •  4
  •   mob    14 年前

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

    # 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
    
        2
  •  6
  •   DVK    14 年前
    ^\s*if\s*\(\S+\s*!
    
    • 使用 \S 对于非空白区域。 \w 不会匹配任何特殊字符,所以 if ($word 不匹配。也许你的规格没问题,在这种情况下 \w (字母数字加上“u” 好吧
    $ 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|
    
        3
  •  1
  •   codaddict    14 年前

    你可以试试:

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

    .

    \t*| *
    

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