如何报告在整个脚本中从未匹配的任何正则表达式?

时间:2017-08-01 09:53:27

标签: python ruby perl awk sed

我经常循环遍历文件中的行并应用多个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!进行调试,并在程序运行完毕后获取所有不匹配的正则表达式的报告。

4 个答案:

答案 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"
        }
    }
}

它只在文件中保留一行文件。