Проблема с использованием цикла while для оценки нескольких строк, Perl - PullRequest
1 голос
/ 04 февраля 2011

Заранее благодарим за то, что потворствовали любительскому вопросу Perl. Я извлекаю некоторые данные из большого неформатированного текстового файла, и у меня возникают проблемы при объединении использования цикла while и сопоставления регулярных выражений в нескольких строках.

Сначала образец данных:

 01-034575 18/12/2007  258,750.00 11,559.00  36       -2     0     6    -3     2    -2     0     2     1    -1     3     0     5    15
                                                      -13   -44   -74  -104  -134  -165  -196  -226  -257  -287  -318  -349  -377  -408  -438
                                                      -469  -510  -541  -572  -602  -633  -663
      Atraso Promedio --->        0.94

Первая последовательность, XX-XXXXXX - это идентификационный номер ссуды. Дата и следующие два числа не важны. «36» - количество платежей. Следующая последовательность положительных и отрицательных чисел показывает, насколько поздно / рано был этот клиент для этого кредита в каждый из 36 периодов оплаты. «0,94», следующее за «Atraso Promedio», является расчетом банка для средней задержки. Проблема в том, что это неправильно, так как они заменяют все отрицательные (то есть досрочные) платежи в серии нулями, фактически подчеркивая, насколько рискован клиент. Мне нужно написать программу, которая извлекает ID и количество платежей, а затем динамически рассчитывает среднюю задержку в несколько строк.

Вот что у меня есть:

#Create an output file
open(OUT, ">out.csv");
print OUT "Loan_ID,Atraso_promedio,Atraso_alt,N_payments,\n";

open(MYINPUTFILE, "<DATA.txt");
while(<MYINPUTFILE>){

    chomp($_);

    if($ID_select != 1 && m/(\d{2}\-\d{6})/){$Loan_ID = $1, $ID_select = 1} 

    if($ID_select == 1 && m/\d{1,2},\d{1,3}\.00\s+\d{1,2},\d{1,3}\.00\s+(\d{1,2})/)  {$N_payments = $1, $Payment_find = 1};

    if($Payment_find == 1 && $ID_select == 1){

            while(m/\s{2,}(\-?\d{1,3})/g){
                $N++; 
                $SUM = $SUM + $1;
                print OUT "$Loan_ID,$1\n"; #THIS SHOWS ME WHAT NUMBERS THE CODE IS GRABBING. ACTUAL OUTPUT WILL BE WRITTEN BELOW
                print $Loan_ID,"\n";
            }


        if(m/---> *(\d*.\d*)/){$Atraso = $1, $Atraso_select = 1}
        if($ID_select == 1 && $Payment_find == 1 && $Atraso_select == 1){
                ...

Это еще не все, но в цикле while происходит сбой программы. Проблема в модификаторе шаблона 'g', который выполняет глобальный поиск строки. Это заставляет программу получать номера, которые мне не нужны, например, «1» в идентификаторе ссуды и «36» для количества платежей. Мне нужно, чтобы цикл while начинался с того места, где прервалась предыдущая строка в коде, которая должна быть сразу после определения количества ссуд. Я перепробовал каждый модификатор шаблона, который мне удалось найти, и только «g» удерживает меня в бесконечном цикле. Мне нужно, чтобы цикл while шел до конца строки, а затем начинал со следующей, не прочесывая части строки, уже переданные через программу.

Мысли? Имеет ли это смысл? Был бы безмерно благодарен за любую помощь, которую вы можете предложить. Эта работа бесплатна, неоплачиваема: просто пытаюсь помочь друзьям в микрокредитном учреждении провести анализ рисков.

Приветствия
Аарон

Ответы [ 3 ]

2 голосов
/ 04 февраля 2011

Проблема, вероятно, проще с использованием split, например, что-то вроде этого:

use strict;
use warnings;

open DATA, "<DATA.txt" or die "$!";

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

while(<DATA>)
{
    if(/\b\d{2}-\d{6}\b/)
    {
        ($loanNumber, undef, undef, undef, $numberOfPayments, @payments) = split;
    }
    elsif(/Atraso Promedio/)
    {
        my (undef, undef, undef, $atrasoPromedio) = split;

        # Calculate average of payments and print results

    }
    else
    {
        push(@payments, split);
    }
}
0 голосов
/ 04 февраля 2011

Ответ Питера ван Хейдена - хорошее упрощение для решения.

Чтобы ответить на вопрос оператора о том, чтобы регулярное выражение продолжалось там, где оно остановилось, см. Операторы Perl - операторы, подобные регулярному выражению , в частности, раздел «Сопоставление в контексте списка» и «\ G». утверждение "сразу после этого.

По сути, вы можете использовать m//gc вместе с утверждением \G, чтобы использовать совпадение с регулярными выражениями там, где прервались предыдущие совпадения.

Пример, приведенный в разделе "\ G assertion" о лексоподобных сканерах, может показаться применимым к этому вопросу.

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

Если данные достаточно чистые, я мог бы подойти к ним, используя split вместо регулярных выражений. Первая строка является идентифицируемой, если поле [0] соответствует форме номера займа, а поле [1] соответствует формату даты; тогда даты платежа представляют собой фрагмент поля [5 ..- 1]. Аналогично, тестирование первого поля каждой строки показывает, где вы находитесь в данных.

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