Grep& Perl正则表达式负面看起来不起作用

时间:2016-06-07 10:08:04

标签: regex perl grep

我想在grep + perl中使用正则表达式,以便在 finally 子句中选择 unclosed java语句。

我想出的模式应该选择所有.submitBacth();其中没有最终{

然而,由于所有比赛都被退回,所以背后的负面看起来并不正常或正常工作。

myself@mymachine:~/Desktop$ grep -C 3 -P '(?s)(?<!finally\s\{.).*?\.submitBatch\(\)\;' ~/myfile.txt

示例文本(myfile.txt):

        //sample text
        batch.addToBatchUpdate(item1);
    }
    batch.submitBatch();
    dao.update(item2);
    //another text
} finally {

--

        }
    }
} finally {
    impl.submitBatch();
    test.close();
}

预期输出应为:

                //sample text
                batch.addToBatchUpdate(item1);
            }
            batch.submitBatch();
            dao.update(item2);
            //anotehr text
        } finally {

我预计只会看到第一个条目batch.submitBatch();但正如你所看到的那样都会被退回。

2 个答案:

答案 0 :(得分:1)

在Perl中你可以使用

$regex_new = /( (?:finally\s+\{\s+|.) )(\S+\.submitBatch\(\)\; ) /sx;

从文件中提取.submitBatch的子字符串。如果第一个捕获组($1的内容)以finally开头,则可以忽略该匹配(因为您要排除这些匹配)。

关于你原来的正则表达式,

$regex = /( (?<!finally\s\{.) .*? \.submitBatch\(\)\; )/sx;

这里有什么问题?它将匹配远远超过需要的内容,并且很难提取您正在寻找的匹配项。

例如:

use feature qw(say state);
use strict;
use warnings;

use Term::ANSIColor;

my $str = do { local $/; <DATA> };
my $regex = /( (?<!finally\s\{.) .*? \.submitBatch\(\)\; )/sx;
$str =~ s/$regex/color_match( $1 )/ge;
say $str;

sub color_match {
    state $i = 0;
    state $colors = [qw[red green blue]];
    return color( "bold " . $colors->[$i++] ) . $_[0] . color("reset");
}

__DATA__
         ... code ...
       } finally {
         impl.submitBatch();
         test.close();
     }
     batch.addToBatchUpdate(item1);
  }
  batch.submitBatch();
  dao.update(item2);
  //another text
} finally {
  impl.submitBatch();
  test.close();
}

输出结果为:

enter image description here

因此,每个匹配都以.submitBatch();结束,但负面的后置断言(?<!finally\s\{.)会立即匹配g修饰符的每次迭代。例如,对于第一次迭代,它在文件的开头匹配,然后.*?匹配所有直到第一个.submitBatch();并且完成第一次迭代(不需要回溯)。同样适用于其他比赛。

如果我们将$regex替换为$regex_new,则输出将为:

enter image description here

现在很容易排除错误匹配。 例如,您可以使用e修饰符:

$str =~ s/$regex/fix_missing_finally_clause( $1, $2)/ge;

其中(例如):

sub fix_missing_finally_clause {
    if ($_[0] =~ /^finally/ ) {
        return $_[0].$_[1];
    }  
    else {
        # Insert your edits here... for example:
        return "finally {\n" . $_[0] . $_[1] . "\n\t}\n";
    }
}

答案 1 :(得分:1)

感谢Håkon的详细解答,但我更喜欢使用grep的perl扩展,因为我有其他正则表达式,我不想重写perl中的所有脚本(我喜欢保持我的脚本像整洁一样可能),即使可能更容易。 我终于设法修复了这个正则表达式,它也注意在方法签名和我感兴趣的方法之间查看。

我知道正则表达式选择太多,但我不是专家,我对替换不感兴趣,所以只要有匹配就足够了。

myself@mymachine:~$grep -Pzo '(?s)(?<=public|private|protected).(?<!finally).*?\.submitBatch\(\)\;' /tmp/test.java
     method
    //sample text
            batch.addToBatchUpdate(item1);
        }
        batch.submitBatch();