2012-08-07 103 views
2

我在写一个perl脚本来解析标准输入中的制表符分隔数据。使用正则表达式/ Perl解析日期列

该脚本删除前导空白和尾随空白,空白字符串为“NULL”的任何字段,并将日期列从“MMM DD YYYY HH:MM:SS:SSSAM”格式重新格式化为“YYYYMMDD”格式。

样品输入:

93092 Apr 1 2010 12:00:00:000AM  59668370.60702875 
22341 Apr 1 2010 12:00:00:000AM  51309196.84639429 
27844 Apr 1 2010 12:00:00:000AM  NULL 
150465 Apr 22 2010 12:00:00:000AM  19706190.97586569 
119364 Jul 20 2010 12:00:00:000AM  16335977.41009162 

目标产出:

93092|20100401|59668370.60702875 
22341|20100401|51309196.84639429 
27844|20100401| 
150465|20100422|19706190.97586569 
119364|20100720|16335977.41009162 

脚本接受表示它们具有需要转换的日期的列(多个)参数。在上面的示例中,我将以“1”作为参数调用,因为第二列是需要转换的日期。多列将由逗号分隔列表表示。

这是我迄今为止能够做到的。

#!/usr/bin/perl 
my @date_cols = split(/,/, $ARGV[0]); 

while (<STDIN>) { 
    my @fields = split(/\t/, $_, -1); 
    for (@fields) { 
     s/^\s+//; 
     s/\s+\z//; 
     s/^NULL\z//; 
    } 
    for (@fields[@date_cols]) { 
##NEED HELP WITH DATE FORMATTING 
    } 

    print(join('|', @fields), "\n"); 
} 
+1

是您的文件制表符分隔的吗?否则,你的第二列(空白)只是一个月,而不是整个日期。 – chepner 2012-08-07 15:35:34

+2

我建议使用像[DateTime :: Format :: Strptime](https://metacpan.org/module/DateTime::Format::Strptime)这样的模块来处理这个细节。格式化来自[DateTime](https://metacpan.org/module/DateTime)对象的日期在这一点上变得微不足道。 – zostay 2012-08-07 15:39:26

+1

或者也许Time :: Piece - 这是在Perl核心发行版中。 – 2012-08-07 15:52:15

回答

1

使用Time::Piece很简单,很容易为您提供日期格式。使用strptime函数可以定义要使用的模式; strftime函数可让您生成所需的输出格式。考虑:

use Time::Piece; 
my $date = "Apr 1 2012 12:00:00AM"; 
my $t = Time::Piece->strptime($date,"%b %d %Y %H:%M:%S%p"); 
print $t->strftime("%Y%m%d\n"); 

这种方法的一个很好的功能是,一个或两个空格分隔月份和日期字段并不重要;结果是一样的。

+0

日期格式在秒内包含附加:000。我能够改变你的例子在strptime函数中包含“:000”。 'my $ t = Time :: Piece-> strptime($ _,“%b%d%Y%H:%M:%S:000%p”);'现在这部分工作。我试图将其插入原始脚本中,并且出现错误“解析时间错误/usr/lib/perl5/5.10.0/x86_64-linux-thread-multi/Time/Piece.pm line 470, line 1.” (@fields [@date_cols])my $ t = Time :: Piece-> strptime($ _,“%b%d%Y%H:%M:%S:000%p”); my $ s = $ t-> strftime(“%Y%m%d \ n”); splice(@ fields,@ date_cols,1,$ s); }' – DataTsar 2012-08-07 18:31:23

+0

其实......这个效果很好。我发现了一个导致我的问题的类型o。谢谢你的帮助! – DataTsar 2012-08-07 18:39:40

0

基于戴夫交叉的建议上面使用Time::Piece

use Time::Piece; 

while (<STDIN>) { 
    # Split each row into columns by white space 
    my @fields = split /\s+/; 

    # Rebuild the date ("Apr 1 2010") from columns 2 through 4 
    my $time_field = join ' ', @fields[1..3]; 

    # Parse the date - see man strptime 
    my $date = Time::Piece->strptime($time_field, '%B %d %Y'); 

    # Format the output - see man strftime 
    print join '|', $fields[0], $date->strftime('%Y%m%d'), $fields[5]; 
} 

正则表达式是一个非常优秀的工具,但日期是丑陋的(甚至令人咋舌)。只要有可能,我宁愿使用已经存在的库来解析它们。

+0

我不确定在空白处解析是否是最好的选择,因为在输入文件和数学中可能有多个日期字段,以确定哪些列表示日期会很快变得复杂。 – DataTsar 2012-08-07 18:19:01