帮助编写灵活的分裂,perl

时间:2011-02-18 05:51:13

标签: perl

几周前,我发布了一个关于我正在解析不规则格式的数据文件的问题。以下是数据样本:

01-021412 15/02/2007  207,000.00 14,839.00  18       -6     2     6     6     5    16     6     4     4     3   -28   -59   -88  -119
                                                     -149  -191  -215  -246             
     Atraso Promedio --->        2.88

我需要一个程序,它将提取01-021412,18,计算并汇总后续系列中的所有数字,并存储atraso promedio,这可能会重复此操作超过40,000个。我收到了一个非常有帮助的response,从中可以编写代码:

use strict;
use warnings;

#Create an output file
open(OUT, ">outFull.csv");
print OUT "loanID,nPayments,atrasoPromedio,atrasoAlt,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72\n";

open(MYINPUTFILE, "<DATOS HISTORICO ASPIRE2.txt");

my @payments;
my $numberOfPayments;
my $loanNumber;

while(<MYINPUTFILE>)
{
    if(/\b\d{2}-\d{6}\b/)
    {
        ($loanNumber, undef, undef, undef, $numberOfPayments, @payments) = split;
    }
    elsif(m/---> *(\d*.\d*)/)
    {
        my (undef, undef, undef, $atrasoPromedio) = split;
        my $N = scalar @payments;
        print "$numberOfPayments,$N,$loanNumber\n";

        if($N==$numberOfPayments){

        my $total = 0; 
        ($total+=$_) for @payments; 

        my $atrasoAlt = $total/$N; 

        print OUT "$loanNumber,$numberOfPayments,$atrasoPromedio,$atrasoAlt,",join( ',', @payments),"\n";
       }
    }
    else
    {
        push(@payments, split);
    }
}

这样可以正常工作,除了大约50%的条目包含如下的'*'这一事实:

* 01-051948 06/03/2009  424,350.00 17,315.00  48        0     6    -2     0    21    10     9    13    10     9     7    13     3     4
                                                        12    -3    14     8     6
       Atraso Promedio --->        3.02

星号会导致程序失败,因为它会中断拆分模式,从而导致不正确的变量分配。到目前为止,我已经通过从输入数据文件中删除星号来解决这个问题,但我刚刚意识到,通过这样做,程序实际上完全省略了这些贷款。是否有一种经济的方法来修改我的脚本,以便它处理有和没有星号的条目?

顺便说一句,如果一个条目确实包含一个星号,我想在输出数据中记录这个事实。

非常感谢, 亚伦

4 个答案:

答案 0 :(得分:1)

使用中间数组:

my $has_asterisk;

# ...

if(/\b\d{2}-\d{6}\b/)
{
    my @fields = split;
    $has_asterisk = $fields[0] eq '*';
    shift @fields if $has_asterisk;
    ($loanNumber, undef, undef, undef, $numberOfPayments, @payments) = @fields;
}

答案 1 :(得分:1)

您可以在进行拆分之前丢弃星号:

while(<MYINPUTFILE>) {
    s/^\s*\*\s*//;

    if(/\b\d{2}-\d{6}\b/) {
        ($loanNumber, undef, undef, undef, $numberOfPayments, @payments) = split;
    ...    

除此之外,你应该使用3个args open,lexical filehandles并测试打开失败。

my $file = 'DATOS HISTORICO ASPIRE2.txt';
open my $MYINPUTFILE, '<', $file or die "unable to open '$file' for reading : $!";

答案 2 :(得分:0)

所以看起来你的第一个if语句正则表达式没有考虑'*',那么我们如何修改它。我的perl正则表达式技巧有点生疏,请注意这是未经测试的。

if(/(?:\* )?\b\d{2}-\d{6}\b/)

*是一个修饰符,表示“零次或多次”,因此我们需要将其转义,\*

(?: )表示“将它们组合在一起但不保存”,我只是使用它,以便我可以同时将?应用于空格和*

答案 3 :(得分:0)

while循环开始时,试试这个:

...
while(<MYINPUTFILE>)
{
    my $asterisk_exists = 0;
    if (s/^\* //) {
       $asterisk_exists = 1;
    }
...

除了使用s///功能删除星号外,您还可以首先跟踪星号是否在那里。删除星号后,脚本的其余部分应该正常运行。

相关问题