在 Perl 中,将变量设置为正则表达式,我收到一个未初始化的值警告

In Perl, set a variable to a regex, and I get an uninitialized value warning

提问人:user1428649 提问时间:11/30/2019 最后编辑:glennsluser1428649 更新时间:12/7/2019 访问量:109

问:

因此,我有这个代码块,用于分析传递到 CGI 调用的参数值。

我有这个代码块来做这件事。

if (defined($passed_args->{'between'})) {
    my $between = $passed_args->{'between'};
        my $date_field = @$between[0];
        my $start_date = @$between[1];
        my $end_date   = @$between[2];
        my $gdt_regex  = /[0-9]{4}(-)((0[1-9])|(1[0-2]))(-)((0[1-9])|([1-2][0-9])|(3[0-1]))(\s)(([0-1][0-9])|(2[0-3])):([0-5][0-9]):([0-5][0-9])/;

        if (!defined($passed_args->{$date_field}) && $start_date =~ $gdt_regex && $end_date =~ $gdt_regex) {
            $self->error('between parameter not populated correctly.');
            return;
        }

        $query_url .= $date_field . "BETWEEN" . $start_date . "@" . $end_date . "^";

    delete $passed_args->{'between'};

}

start_date 和 end_date 的值采用如下格式:

2019-04-04 00:00:00

在我的服务器日志中,我反复收到以下警告:

Use of uninitialized value $_ in pattern match (m//) at /my/script.pm line 6316

第 6316 行对应:

my $gdt_regex = /[0-9]{4}(-)((0[1-9])|(1[0-2]))(-)((0[1-9])|([1-2][0-9])|(3[0-1]))(\s)(([0-1][0-9])|(2[0-3])):([0-5][0-9]):([0-5][0-9])/;

因此,据我所知,在使用未初始化的值进行模式匹配时,您会遇到该错误。然而,当我为变量分配正则表达式时,为什么我会得到它?捕获组是否有什么原因导致 Perl 陷入困境?还是我错过了别的东西?

据我所知,这并没有造成任何伤害,但这经常出现在我的日志中,我想清除它。

正则表达式 Perl 变量 警告

评论

0赞 ikegami 11/30/2019
提示:应该是 .(如果在使用名称时使用,则在使用 ref 时使用。更好的是,您应该使用更清晰的 .@$between[0]$$between[0]$a[0]$$ref[0]$between->[0]
0赞 ikegami 11/30/2019
提示:该模式应具有前导和尾随,以确保在日期之前或之后没有任何内容。^\z
0赞 ikegami 11/30/2019
提示:模式中的所有参数都会导致不必要的捕获。你正在使模式比它需要的更复杂,而且速度更慢。 可以写成 ,您应该使用 而不是 to 分组交替而不捕获。(-)-(?:...)(...)

答:

3赞 ikegami 11/30/2019 #1

/.../是匹配运算符。它检查模式是否与绑定变量匹配。如果没有显式绑定变量,则它与 against 匹配,就像您使用了 一样。$_$_ =~ /.../

您正在寻找

my $gdt_regex = qr/.../;
1赞 Polar Bear 11/30/2019 #2

好吧,我认为一些验证对您的代码有益

注意:可能并且更适合与$date_startdate_end$date_field

use strict;
use warnings;

........

if (defined($passed_args->{'between'})) {
    my($date_field,$date_start,$date_end) = @{$passed_args->{between}}[0..2];

    {
        $self->error('ERROR: between parameter not populated correctly.');
        return;
    } if ( !defined($passed_args->{$date_field}) 
        && !is_valid($date_start) 
        && !is_valid($date_end)
    ) 

    $query_url .= $date_field . "BETWEEN" . $start_date . "@" . $end_date . "^";

    delete $passed_args->{'between'};

}

#
# timestamp validation
#
sub is_valid {
    my $timestamp = shift;

    return 0 if $timestamp !~ /\d{4}-\d{2}-\d{\2} \d{2}:\d{2}:\d{2}/;

    my($date,$time)         = split ' ', $timestamp;
    my($year,$month,$day)   = split '-', $date;
    my($hour,$min,$sec)     = split ':', $time;

    #return 0 if $year  < 1900 or $year  > 2019;
    return 0 if $month < 1    or $month > 12;
    return 0 if $day   < 1    or $day   > 31;
    return 0 if $hour  < 1    or $hour  > 23;
    return 0 if $min   < 1    or $min   > 59;
    return 0 if $sec   < 1    or $sec   > 59;

    return 1;   # timestamp is valid
}

评论

0赞 Toto 11/30/2019
你的潜艇没用,你为什么要把年份限制在和之间?你为什么不接受?你为什么接受?使用实时日期时间验证或不使用它。is_valid19002019month = 121900-02-29
1赞 ikegami 12/1/2019
除非后面跟着流控制操作(、、等),否则不应使用 // 。所以应该是.1) 使用 // 会降低可读性。符号用于 // 是有原因的。2) ,并且优先级非常低,这最终会咬你。事实上,由于使用了错误的运算符,您有一个优先级错误。(我修好了。andornotdienextreturn$day < 1 or $day > 31$day < 1 || $day > 31andornot&&||!andornot
0赞 ikegami 12/1/2019
我确实认为从表达式中删除范围检查的建议是一件好事。速度稍慢,但可读性更强。
0赞 Polar Bear 12/1/2019
帖子中的@Toto正则表达式接受从 0000 到 9999 的年份——这非常有用!我不认为计算机在 1936 年之前就已经存在了。好的,第 12 个月对我的验证有效,但在 perl 中,月份编号从 0 - tutorialspoint.com/perl/perl_date_time.htm 开始。
0赞 Polar Bear 12/1/2019
@ikegami -- 谢谢你的修复,当我写下答案时已经太晚了。我正在做一些常规项目,需要一些转移来转移我的注意力来改变——这个问题就是这个小小的转移。