2011-02-04 5 views
1

아마추어 Perl 질문에 미리 감사드립니다. 큰 포맷되지 않은 텍스트 파일에서 일부 데이터를 추출하고 'while'루프와 정규 표현식을 여러 줄에 걸쳐 사용하는 것을 결합하는 데 문제가 있습니다.'while'루프를 사용하여 여러 행을 평가하는 데 문제가 있습니다. Perl

우선, 데이터의 샘플 :

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는 임대 ID 번호이다. 날짜와 다음 두 숫자는 중요하지 않습니다. '36'은 지불 횟수입니다. 다음의 양수 및 음수 순서는이 고객이 36 개의 지불 기간마다이 대출에 얼마나 늦었/빠를지를 나타냅니다. 'Atraso Promedio'다음의 '0.94'는 평균 지연에 대한 은행의 계산입니다. 문제는 그것이 잘못된 것입니다. 왜냐하면 일련의 모든 부정 (즉, 조기) 지급을 0으로 대체하여 고객이 얼마나 위험한지를 효과적으로 과장하기 때문입니다. 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'에 있습니다. 이렇게하면 대출 ID에 '1', 지불 횟수에 '36'과 같이 원하지 않는 번호를 얻을 수 있습니다. 코드에서 이전 줄이 끝난 곳에서 시작하는 while 루프가 필요합니다.이 줄은 대출 수가 식별 된 직후에 있어야합니다. 내가 볼 수 있었던 모든 패턴 한정자를 시도했는데 'g'만이 나를 무한 루프에서 빠져 나간다. while 루프가 라인의 끝으로 가야하고, 프로그램을 통해 이미 공급 된 문자열의 부분을 빗질하지 않고 다음 라인에서 시작해야합니다.

생각하십니까? 이게 말이 돼? 당신이 제공 할 수있는 도움에 대해 대단히 감사 할 것입니다. 이 작업은 무보수입니다. 마이크로 대출 기관에서 친구를 도우려는 시도는 위험 분석을 실시합니다. 나는 정기적으로 대신 분할을 사용하여 접근 할 수있는 충분한 깨끗한 데이터의 경우,

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); 
    } 
} 

답변

2

문제는이 같은 인스턴스 뭔가, 분할을 사용하는 것이 더 쉬울 것입니다 표현. 필드 [0]이 대출 번호 형식과 일치하고 필드 [1]이 날짜 형식과 일치하면 첫 번째 줄을 식별 할 수 있습니다. 지불 날짜는 필드 [5 ..- 1]의 배열 슬라이스입니다. 마찬가지로 각 행의 첫 번째 필드를 테스트하면 데이터의 현재 위치를 알 수 있습니다.

+0

많은 조언을드립니다. 분할은 내가 필요한 것입니다. – Aaron

0

:

건배,
아론

0

Peter van her Heijden의 답변은 솔루션을 간단하게 정리 한 것입니다.

regexp를 중단 한 부분부터 계속하려면 OP의 질문에 대답하려면 Perl operators - regexp-quote-like operators, 특히 "목록 컨텍스트에서 일치"섹션과 그 직후 "\ G 명제"섹션을 참조하십시오.

기본적으로 m//gc\G 어설 션을 사용하면 이전 일치 항목을 사용하지 않은 정규식 일치를 사용할 수 있습니다.

lex와 유사한 스캐너에 대한 "\ G 단정"절의 예제가이 질문에 적용되는 것처럼 보입니다.

관련 문제