正则表达式和哈希

时间:2014-03-24 14:42:48

标签: perl

我正在尝试使用哈希将201302_1形式的字符串转换为2013-02-09。不幸的是,我对Perl的了解相当有限,我还没有完成它的工作。

BEGIN {
    use strict;
    use warnings;
    use 5.010;

    my %cycle = qw (
      1 '09'  2 '12'  3 '12'  4 '18'  5 '21'
      6 '24'  7 '27'  8 '01'  9 '03'  10 '06'
    );
}

s/(\d{4})(\d{2})_(\d+)$/$1-$2-$cycle{$3}/g

如果此脚本还解决了在$2为8,9或10时添加1个月(增加$1并最终$3)的问题,那就太棒了。

我从终端运行perl -p script.pl sample.txt

编辑:我最后根据似乎有用的答案编写了以下内容:

my %cycle = qw (
  1 09  2 12  3 12  4 18  5 21
  6 24  7 27  8 01  9 03  10 06
);
s{(\d{4})(\d{2})_(\d+)1\.csv$}{
  my @r = (undef, $1, $2, $3);
  if ($3 > 7) {
    $r[2] = sprintf("%02d", $r[2]+1);
  }
  if ($r[2] > 12) {
    $r[2] = "01";
    $r[1] = $r[1] + 1;
  }
  "$r[1]-$r[2]-$cycle{$r[3]}";
}ge;

3 个答案:

答案 0 :(得分:4)

您的严格和警告仅限于BEGIN块,因此您没有看到结果的警告,因为%cycle 仅作用于开始块,而另一个(空)%循环哈希实际上用于替换。

尝试

use strict;
use warnings;
use 5.010;
my %cycle;
BEGIN {
    %cycle = ...

由于您计划调整月份和年份,我会避免替换,而是执行:

my ($year, $month, $cycle) = /\A(\d{4})(\d{2})_(\d+)\z/ or die "bad input: $_\n";
my $day = $cycle{$cycle};
if ( $cycle >= 8 ) {  # or have a second hash that indicates "following month"

答案 1 :(得分:2)

使用正则表达式解决日期数学通常不是一个好主意,因为它相当复杂并且充满了边缘情况。请改用Time::Piece

use strict;
use warnings;
use Time::Piece;

my %cycle = qw (
  1 09  2 12  3 12  4 18  5 21
  6 24  7 27  8 01  9 03  10 06
);

while (<DATA>) {
    chomp;
    s/_(\d+)$/$cycle{$1}/;
    my $t = Time::Piece->strptime($_, "%Y%m%d");
    $t = $t->add_months(1);
    print $t->strftime("%Y-%m-%d");

}

__DATA__
201302_1

我已经猜到(因为你没有说)%cycle中的值是天,因此可以像天一样对待。因此,我们只需使用哈希中的“日期”替换数字,然后使用strptime解析日期,添加一个月,然后使用strftime打印日期。

请注意,此代码假定整个字符串是日期,因此您可能需要调整它以用于其他类型的输入。

另请注意,您可以将<DATA>更改为<>以像以前一样使用脚本,但不使用-p开关,即:

perl script.pl sample.txt

答案 2 :(得分:0)

use strict;
use warnings; 
use 5.010;

use DateTime; 

my $input = $ARGV[0];

my %cycle2day = ( 1 => 9,  2 => 12, 3 => 12, 4 =>18, 5 => 21,
                  6 => 24, 7 => 27, 8 => 1, 9 => 3, 10 => 6,
);

my ($year, $month, $cycle) = $input =~ /(\d{4})(\d{2})_(\d+)/;

unless (grep { $cycle == $_ } keys %cycle2day) { 
    die "Unknown cycle $cycle!";
}

my $date = DateTime->new( year => $year,
                          month => $month,
                          day => $cycle2day{$cycle},
                        );

if ( $cycle == 8 or $cycle == 9 or $cycle == 10 ) {
    $date->add(months => 1);
}

say $date->ymd;

输出:

C:\>perl test_cycle.pl 201302_1
2013-02-09

C:\>perl test_cycle.pl 201302_9
2013-03-03