不在 perl 中返回匹配的正则表达式字符

问题描述 投票:0回答:2

尝试自学 perl 和正则表达式。

想知道如果用户在姓氏中输入 Smith+,如何返回“+”。如“用户在姓氏字段中输入了无效字符,特别是“+”。”

unless (    $string1 =~ m/^[\w\.\s\-]+$/        &&  #last name must contain only words, periods, spaces and dashes
            $string2 =~ m/^[\w\.\s\-\@]+$/      &&  #email must contain only words, periods, spaces and dashes and at symbols
            $string3 eq "Find Order"            &&  #submit button field must match Find Order
            $string1 ne ''                      &&  #last name can't be empty
            $string2 ne ''                          #email can't be empty
       )
       {
       print "$& $1 $` $'";    #these don't return anything and it makes me sad
       &error;
       }
regex perl cgi
2个回答
0
投票

我稍后会回答你的正则表达式问题,但首先要对特定问题进行一些思考。因为你只是在学习,所以随心所欲地做玩具程序和实验不是问题,但一旦你开始做真正的工作,还有一些其他的事情可以让你的生活更轻松。

我已经用经过很多规则的代码完成了这种事情,而不关心它们是什么。在此示例中,

@rules
是代码引用列表。如果规则失败,它会返回描述违规情况的已定义字符串。否则它什么都不返回,我们跳过它:

foreach my $rule ( @rules ) {
    my $problem = $rule->($test_string);
    next unless defined $problem;
    push @problems, $problem;
    }

这里的优点是问题的实质不取决于规则本身。添加任意数量的规则,此代码不会更改。您不必在每次遇到要检查的新情况时都编辑此代码。相反,您只需从

@rules
.

添加或删除代码引用

所以让我们为允许的字符制定一个规则:

my $test_string = 'Smith+';

my @rules = (
    sub { $_[0] =~ m/ \A [a-z] \z/xi ?
        undef : "Names can contain only letters" },
    );

my @problems;
foreach my $rule ( @rules ) {
    my $problem = $rule->($test_string);
    next unless defined $problem;
    push @problems, $problem;
    }

if( @problems ) { print join "\n", @problems }
else { print "No problems" }

输出:

Names can contain only letters

而且,这种方法允许我一次给用户一个所有问题的列表,而不是在他们发现下一个要解决的问题之前抱怨一个问题让他们解决。我将添加另一个规则。同样,我不必更改用于检查规则的机制。我只是将另一个代码引用添加到代码引用列表中以检查:

my @rules = (
    sub { $_[0] =~ m/ \A [a-z] \z/xi ? undef : "Names can contain only letters" },
    sub { $_[0] =~ m/ \A A-Z /xi ? undef : "Names must start with a capital letter" },
    );

现在输出是:

Names can contain only letters
Names must start with a capital letter

不是说第二个规则应该是规则😼

更有趣的消息

现在,根据您的喜好调整消息和代码参考。但是,请注意,这会检查它是否只包含允许的字符并指定一般规则。这通常就足够了。

但是让我们把这个错误信息变成花哨的购买改变规则以返回一个更漂亮的消息:

my @rules = (
    sub {
        my @not_allowed = $_[0] =~ m/ ([^a-z]) /gxi;
        return unless @not_allowed;

        my %chars = map { $_, 1 } @not_allowed;
        my @chars = sort keys %chars;
        "Names can contain only letters. $_[0] also has @chars"
        },
    );

我本可以打高尔夫球,但我不会。代码 ref 现在开始匹配所有不允许的单个字符。列表上下文中的全局匹配 (

\g
) 返回所有捕获。如果没有捕获,则没有违反规则,我什么也不返回。否则,我会做很多工作来对字符列表进行 uniq 并将它们添加到消息中。现在输出是:

Names can contain only letters. Smith+ also has +

一般来说,我不认为额外的工作是值得的。


-1
投票

一种方法是明确测试不良字符和/或条件

if ( $string1 eq '' ) { 
    say "Name can't be empty";
    error();
}
elsif ( my @bad_namechars = $string1 =~ /([^\w.\s-])/g ) { 
    say "Character(s) \"@bad_chars\" aren't expected in a name";
    error();
}
elsif ( $string2 eq '' ) { ... }
elsif ( my @bad_emailchars =~ /([^\w.\s-\@])/g ) { ... } # etc

如果您更愿意检测所有错误,以便通知用户,然后制作这些独立的

if
语句,并可能在每个语句中设置一个标志,以便能够在所有测试后调用
error()
一次,如果有任何错误(s) 发生了。

虽然可以用其他方式组织这些测试,但具有多个正则表达式的复合测试并不能真正满足规定的需求。每个新的正则表达式都会重置大部分内部变量,并且无论如何都无法判断哪个正则表达式(错误)匹配,因此错误报告将不起作用。

可以通过像上面这样分配捕获的字符串表达式来完成这项工作,但这会导致代码很容易被反对——而且,由于 Perl 的

&&
(和
and
等)运算符短路,那样只能检测到一个错误。

我假设

&error
指的是自定义子;如果是这样,那么可能不需要
&


这仍然只能捕获一个(第一次测试的)错误,因为

or
短路

if ( 
    (my $empty_name = $string1 eq '')        or
    (my @bad_namechars = $string1 =~ /.../)  or
    ... 
) { ... }
© www.soinside.com 2019 - 2024. All rights reserved.