提前感谢您放纵一个业余的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是贷款ID号。日期和以下两个数字并不重要。 '36'是付款次数。以下序列的正数和负数表示该客户在36个付款期间的每一个贷款的延迟/早期。 'Atraso Promedio'之后的'0.94'是银行对平均延迟的计算。问题是它是错误的,因为它们用零替换系列中的所有负(即早期)支付,有效地说明了客户的风险程度。我需要编写一个程序来提取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循环来到行的末尾,然后从下一个循环开始,而不是梳理已经通过程序提供的字符串部分。
思考?这有意义吗?非常感谢您提供的任何帮助。这项工作是无偿的,无偿的:只是试图帮助微型贷款机构的一些朋友进行风险分析。
干杯,
亚伦
答案 0 :(得分:2)
使用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);
}
}
答案 1 :(得分:0)
如果数据足够干净,我可能会使用split而不是正则表达式来处理它。如果field [0]与贷款号码的形式匹配并且字段[1]与日期的格式匹配,则第一行是可识别的;然后付款日期是字段[5 ..- 1]的数组切片。类似地,测试每行的第一个字段可以告诉您数据的位置。
答案 2 :(得分:0)
Peter van她的Heijden的回答是对解决方案的一个很好的简化。
要回答关于让正则表达式从中断处继续的OP的问题,请参阅Perl operators - regexp-quote-like operators,特别是“匹配列表上下文”部分和“\ G断言”部分。
基本上,您可以使用m//gc
和\G
断言来使用前一个匹配项中的regexps匹配。
关于类似lex的扫描仪的“\ G断言”部分中的示例似乎适用于此问题。