Помогите написать гибкий сплит, Perl - PullRequest
1 голос
/ 18 февраля 2011

Пару недель назад я опубликовал вопрос о проблеме, с которой я разбирал файл данных неправильного формата. Вот образец данных:

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, и она могла бы повторить эту операцию для более чем 40000 энтеров. Я получил очень полезный ответ , и из этого смог написать код:

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 ]

1 голос
/ 18 февраля 2011

Вы можете сбросить звездочку перед выполнением разбиения:

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

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

И, кроме этого, вы должны использовать 3 открытых аргумента, лексические файловые дескрипторы и тестировать на наличие ошибок.

1 голос
/ 18 февраля 2011

Использовать промежуточный массив:

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;
}
0 голосов
/ 18 февраля 2011

В начале цикла while попробуйте следующее:

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

Помимо удаления звездочки с помощью функции s///, вы также отслеживаете наличие звездочки или нет.на первом месте.Если звездочка удалена, остальная часть вашего скрипта должна работать как обычно.

0 голосов
/ 18 февраля 2011

, так что похоже, что вы первый, если выражение regex не учитывает это '*', так как насчет того, чтобы изменить его?Мой Perl Regex skillz немного ржавый, обратите внимание, что это не проверено.

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

* - это модификатор, означающий «ноль или более раз», поэтому нам нужно его избежать, \*

(?: ) означает «сгруппируйте это вместе, но не сохраняйте», я просто использую его, чтобы применить ? к пробелу и * одновременно

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...