我经常循环遍历文件中的行并应用多个regexp替换,我有时会犯错误,因此其中一个表达式在任何行上都不匹配。 如何在不使用支票混乱我的代码的情况下找出哪个正则表达式不匹配?是否有任何脚本语言为其提供元编程设施或调试工具? 示例输入:
foo
bar
baz
示例脚本(伪代码):
for each line of the file:
s/foo/lorem/
s/bazzz/ipsum/ # this never matches on any line and should get reported
编辑:我更喜欢Mark Thomas'解决方案,因为我希望逐行读取文件并在第一次匹配后停止应用替换。下次我应该让我的要求更清楚。元编程解决方案会有额外的好处,因为我经常逐行进行更复杂的特定于案例的处理,尽管我认为从答案的灵感中我可能会自己想出一个ruby扩展方法,以便我可以替换{{1使用gsub!
进行调试,并在程序运行完毕后获取所有不匹配的正则表达式的报告。
答案 0 :(得分:2)
在Ruby中,gsub!
修改了字符串,如果找不到模式,则返回nil
:
text = "foo
bar
baz"
replacements = [['foo', 'lorem'], ['bazzz', 'ipsum']]
# or with regexen:
replacements = [[/foo/, 'lorem'], [/bazzz/, 'ipsum']]
replacements.each do |pattern, replacement|
unless text.gsub!(pattern, replacement)
puts "#WARNING: #{pattern} wasn't found"
end
end
puts text
输出:
WARNING: bazzz wasn't found
lorem
bar
baz
请注意,一个接一个地应用替换可能会导致错误。
答案 1 :(得分:1)
不是真正的元编程,但这是一个Perl版本,它计算每个模式匹配的行数。它不会修改输入数据或模式,并且一次只在内存中保留一行输入:
#!/usr/bin/env perl
use strict;
use warnings;
use 5.010;
my @patterns = qw( foo bazzz );
my %matches;
for my $line (<DATA>) {
for my $pat (@patterns) {
if ($line =~ /$pat/) {
$matches{$pat}++;
}
}
}
for my $pat (sort @patterns) {
say "$pat matched no lines" unless $matches{$pat};
}
__DATA__
foo
bar
baz
输出:
bazzz matched no lines
编辑:我多么粗心。你想做替换,而不是匹配!这实际上使它更简单一些,因为Perl正则表达式替换运算符返回执行的替换次数。这是一个修改过的版本:
#!/usr/bin/env perl
use strict;
use warnings;
use 5.010;
my %patterns = ( foo => 'lorem', bazzz => 'ipsum' );
my %matches;
for my $line (<DATA>) {
for my $from (keys %patterns) {
my $to = $patterns{$from};
$matches{$from} += $line =~ s/$from/$to/g;
}
}
for my $pat (sort keys %patterns) {
say "$pat matched no lines" unless $matches{$pat};
}
__DATA__
foo
bar
baz
bazzz matched no lines
答案 2 :(得分:1)
这是一个Ruby脚本:
目前,它打印输出但可以更改为写入文件。
<强> substitutions.txt 强>
foo lorem
bazzz ipsum
qux notfound
<强> example.txt中强>
The foo and bazzz
The foo
The bazzz
and the ugly
subs.rb ,调用:ruby subs.rb example.txt
filename = ARGV[0]
substitutions = File.readlines("substitutions.txt").map(&:split)
used = {}
IO.foreach(filename) do |line|
substitutions.each do |pattern, replacement|
if line.gsub!(pattern, replacement)
used[pattern] = true
break #no more substitutions for this line
end
end
puts line
end
unused = substitutions.map(&:first) - used.keys
unless unused.empty?
puts "Unused patterns:"
puts unused
end
输出:
The lorem and bazzz
The lorem
The ipsum
and the ugly
Unused patterns:
qux
答案 3 :(得分:0)
您只需要:
awk '
BEGIN {
map["foo"] = "lorem"
map["bazzz"] = "ipsum"
}
{
for (re in map) {
cnt[re] += gsub(re,map[re])
}
print
}
END {
for (re in map) {
print re, cnt[re]+0 | "cat>&2"
}
}
' file
以上内容将打印出每次替换的次数 - 按摩以适应,例如:
END {
for (re in map) {
if ( cnt[re] == 0 ) {
print "WARNING: never matched", re | "cat>&2"
}
}
}
它只在文件中保留一行文件。