2

/ezmlm-('weed' または 'return' 以外の単語)\s+/ を正規表現と一致させようとしています。以下は、正しいことを行う foreach ループと、ほぼ正しいことを試みる正規表現を示しています。

#!/usr/bin/perl
use strict;
use warnings;

my @tests = (
    {  msg => "want 'yes', string has ezmlm, but not weed or return",
       str => q[|/usr/local/bin/ezmlm-reject '<snip>'],
    },
    {  msg => "want 'yes', array  has ezmlm, but not weed or return",
       str => [ <DATA> ],
    },
    {  msg => "want 'no' , has ezmlm-weed",
       str => q[|/usr/local/bin/ezmlm-weed '<snip>'],
    },
    {  msg => "want 'no' , doesn't have ezmlm-anything",
       str => q[|/usr/local/bin/else '<snip>'],
    },
    {  msg => "want 'no' , ezmlm email pattern",
       str => q[crazy/but/legal/ezmlm-wacky@example.org],
    },
);

print "foreach regex\n";
foreach ( @tests ) {
    print doit_fe( ref $_->{str} ? @{$_->{str}} : $_->{str} ) ? "yes" : "no";
    print "\t";
    print doit_re( ref $_->{str} ? @{$_->{str}} : $_->{str} ) ? "yes" : "no";
    print "\t<--- $_->{msg}\n";
};

# for both of the following subs:
#   @_ will contain one or more lines of data
#   match the pattern /ezmlm-(any word except 'weed' or 'return')\s+/

sub doit_fe {
    my $has_ezmlm = 0;
    foreach ( @_ ) {
        next if $_ !~ m/ezmlm-(.*?)\s/;
        return 0 if $1 eq 'weed' or $1 eq 'return';
        $has_ezmlm++;
    };
    return $has_ezmlm;
};

sub doit_re { return grep /ezmlm-(?!weed|return)/, @_; };

__DATA__
|/usr/local/bin/ezmlm-reject '<snip>'
|/usr/local/bin/ezmlm-issubn '<snip>'
|/usr/local/bin/ezmlm-send '<snip>'
|/usr/local/bin/ezmlm-archive '<snip>'
|/usr/local/bin/ezmlm-warn '<snip>'

サンプル プログラムの出力は次のとおりです。

foreach regex
yes yes <--- want 'yes', string has ezmlm, but not weed or return
yes yes <--- want 'yes', array  has ezmlm, but not weed or return
no  no  <--- want 'no' , has ezmlm-weed
no  no  <--- want 'no' , doesn't have ezmlm-anything
no  yes <--- want 'no' , ezmlm email pattern

最後の例では、正規表現は失敗し、間抜けではあるが正当な電子メール アドレスに一致します。次のように、否定先読みパターンの後に \s を配置して正規表現を修正すると、次のようになります。

grep /ezmlm-(?!weed|return)\s+/

正規表現はまったく一致しません。負のパターンがどのように機能するかに関係していると思います。私は貪欲でない否定を試みましたが、私を逃れている「perldoc perlre」に埋もれているいくつかの教訓があるようです。単一の正規表現でこれを行うことは可能ですか?

4

1 に答える 1

4

負の先読みはゼロ幅です。つまり、正規表現は

/ezmlm-(?!weed|return)\s+/

は、1 つ以上の空白文字が直後に続く場合にのみ一致します"ezmlm-"

パターン

/ezmlm-(?!weed|return)/

一致します

"crazy/but/legal/ezmlm-wacky@example.org"

orが後に"ezmlm-"続かないためです。"weedy""return"

試す

/ezmlm-(?!weed|return)\S+\s+/

whereは 1 つまたは複数のスペース以外の文字です (または、スペースが続いていても電子メール アドレスを拒否する場合は\S+代わりに使用します)。[^@\s]+

于 2013-04-10T22:38:17.457 に答える