【问题标题】:Help writing flexible splits, perl帮助编写灵活的拆分,perl
【发布时间】:2011-02-18 17:38:58
【问题描述】:

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

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

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

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

提前非常感谢, 亚伦

【问题讨论】:

  • 亲爱的,非常感谢您的建议。不幸的是,我尝试了其中的每一个,但都没有奏效。此外,我试图通过简单地创建一个新的输入文件来解决我一直遇到的问题,并将星号交换为空格,然后在单独的程序中识别正在处理的贷款。出于某种原因,当前的 Perl 脚本只是跳过了带有空格替换星号的外借。任何其他想法都会很棒。谢谢!

标签: perl


【解决方案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;
}

【讨论】:

    【解决方案2】:

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

    while(<MYINPUTFILE>) {
        s/^\s*\*\s*//;
    
        if(/\b\d{2}-\d{6}\b/) {
            ($loanNumber, undef, undef, undef, $numberOfPayments, @payments) = split;
        ...    
    

    除此之外,您还应该使用 3 个 args 打开、词法文件句柄并测试打开是否失败。

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

    【讨论】:

      【解决方案3】:

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

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

      * 是一个修饰符,意思是“零次或多次”,所以我们需要转义它,\*

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

      【讨论】:

        【解决方案4】:

        while 循环的开头,试试这个:

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

        除了使用s/// 函数删除星号之外,您还可以首先跟踪星号是否存在。去掉星号后,脚本的其余部分应该可以正常运行。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-02-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多