我想在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();但正如你所看到的那样都会被退回。
答案 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();
}
输出结果为:
因此,每个匹配都以.submitBatch();
结束,但负面的后置断言(?<!finally\s\{.)
会立即匹配g
修饰符的每次迭代。例如,对于第一次迭代,它在文件的开头匹配,然后.*?
匹配所有直到第一个.submitBatch();
并且完成第一次迭代(不需要回溯)。同样适用于其他比赛。
如果我们将$regex
替换为$regex_new
,则输出将为:
现在很容易排除错误匹配。
例如,您可以使用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();