L02 TIME DEPOSITS 489,26,45,422.92
L18 DRAFTS ACCOUNT (IF CREDIT) 10,063.00 10,063.00
L21 SBI BILLS ACCOUNT (CONTRA) A18 37,51,432.00
A12A DEMAND LOANS 4,39,13,597.30
这些是我文件中的行我想要从每行(L或A)开始提取金额并存储到变量中。
这就是我写的
pattern =/[A-Z]\w+\s*([\d,.]*)\s*([\d,.])*/g
$first = $1;
$second= $2;
答案 0 :(得分:1)
你的正则表达式在中间寻找一串\w
和然后空格,因此它不能匹配多个单词。最后一个*
应该在括号内,就像第一个(但见下文)。 [A-Z]
匹配任何块资金,而您表示需要A
或L
,因此请改用[AL]
。
my @amounts = $string =~ /^[AL]\w+ \s+ [A-Za-z ]* ([\d,.]*)/xg;
您不希望使用*
量词重复该模式,以便考虑可变数量的事件。当需求变化时2变为3会怎样?四?相反,您可以捕获数组中的所有匹配并获得与之相同的数量。
/x
允许我们在里面使用空格以便于阅读。
这是另一种更灵活的方法。
您需要一个包含任何数字的模式,,
(逗号),.
(句点) - 并且只能在字符串中使用。您只希望在以A
或L
开头的行中使用此功能。
因此,请跳过不以A
或L
开头的行,然后仅匹配所需的模式。
use warnings;
use strict;
my $filename = '...';
open my $fh, '<', $filename or die "Can't open $filename: $!";
while (<$fh>)
{
next unless /^[AL]/; # skip if the line doesn't start with A or Z
my @amounts = $_ =~ /\b ([\d,.]+) \b/xg;
print "@amounts\n" if @amounts;
}
close $fh;
在这里,您需要指定\b
,字边界。否则,02
中的L02
会匹配,例如。
如果没有匹配,则数组为空,因此我们测试,不打印空行。调整合适。
减少对正则表达式详细信息的依赖并使代码更加灵活的下一步是split按空格划分的行和逐个处理的行。然后调整就容易得多,可以吸收变化。
例如,这有助于评论中提到的数据更改 - 如果有日期会怎么样?上面的正则表达式将匹配数字部分,而第一个正则表达式将崩溃。
在每一行的字段上循环,我们可以跳过日期next if /\d{4}-\d{2}/;