正则表达式:匹配两个捕获组中的不平衡和平衡字符串

时间:2014-04-26 00:42:16

标签: regex perl

我与regex匹配相当不错,但下面的这个让我在周五下午难倒。我在" date"中有以下3个字符串的变体。我需要发送到MySQL作为范围的格式,以获取之间的匹配结果。作为背景,数据来自我无法控制的JSON来源,并且在传递给Perl之前由MySQL处理。除了最后一个版本,一切都很好。

要匹配的变体

2014-04-01~2014-04-16
~2014-04-16
2014-04-01~

第一个是范围。第二个是从时间开始到日期,最后一个是从日期到结束时间。

当前正则表达式

/(\d{4}-\d{2}-\d{2})~|~(\d{4}-\d{2}-\d{2})/g;

Regex101

现在我经历了大量的Regex组合,所列出的组合仅仅是我与之合作的最后一个组合。

问题是我需要将日期指定为fromto。这个很好,因为我有两个日期,因为我有两个捕获组,只有开始时间没关系,因为它自动成为第一个捕获组,但我遇到困难的时候只有#34;从开始时间开始至日期"用于放置在第一个捕获组中,如下所示,我希望它在第二个捕获组中。

Perl中的用法示例

my $date = '~2014-04-01';

my ($f,$t) = $date =~ /(\d{4}-\d{2}-\d{2})/gm;
print "FROM: " . $f . "\n";
print "TO: " . $t . "\n";

我不想在regex中使用多个perl模式,并且希望将perl仅限于上述regex举重。

在这种情况下,任何人都可以为regex提供解决方案吗?

2 个答案:

答案 0 :(得分:2)

use strict;
use warnings;

while (<DATA>) {
    if (/(\d{4}-\d{2}-\d{2})?~(\d{4}-\d{2}-\d{2})?/) {
        if (defined $1 && defined $2) {
            print "a range <$1> to <$2>\n";

        } elsif (defined $1) {
            print "a start <$1>\n";

        } elsif (defined $2) {
            print "a stop <$2>\n";

        } else {
            print "just a ~, ignore\n";
        }
    }
}

__DATA__
2014-04-01~2014-04-16
~2014-04-16
2014-04-01~

输出:

a range <2014-04-01> to <2014-04-16>
a stop <2014-04-16>
a start <2014-04-01>

答案 1 :(得分:0)

这是我的解决方案。请注意,我定义了$date来保存正则表达式的重复部分。我认为这有助于提高可读性。

#!/usr/bin/perl -w

use strict;
use warnings;

my $date = q(\d{4}-\d{2}-\d{2});
my ($from, $to);

while (<DATA>) {
    chomp;

    if (/^($date)~($date)$|^(~)($date)$|^($date)(~)$/) {
    #     ^^^^^^^^^^^^^^^   ^^^^^^^^^^   ^^^^^^^^^^
    #           (1)             (2)          (3)

        ($from, $to) = ($1, $2) if defined($1);  # pattern (1)
        ($from, $to) = ($3, $4) if defined($3);  # pattern (2)
        ($from, $to) = ($5, $6) if defined($5);  # pattern (3)

        print $_, " => [$from][$to]\n";
    }
}

__END__
2014-04-01~2014-04-16
~2014-04-16
2014-04-01~

预期输出

2014-04-01~2014-04-16 => [2014-04-01][2014-04-16]
~2014-04-16 => [~][2014-04-16]
2014-04-01~ => [2014-04-01][~]