假设我有一个如下文件:
我想将所有十进制数存储在哈希值中。
hello world 10 20
world 10 10 10 10 hello 20
hello 30 20 10 world 10
我在看this
这很好用:
> perl -lne 'push @a,/\d+/g;END{print "@a"}' temp
10 20 10 10 10 10 20 30 20 10 10
然后我需要的是计算每个正则表达式的出现次数。
为此我认为将所有匹配存储在散列中并为每个键分配递增值会更好。
所以我试过了:
perl -lne '$a{$1}++ for ($_=~/(\d+)/g);END{foreach(keys %a){print "$_.$a{$_}"}}' temp
给出了输出:
> perl -lne '$a{$1}++ for ($_=~/(\d+)/g);END{foreach(keys %a){print "$_.$a{$_}"}}' temp
10.4
20.7
如果我错了,有人可以纠正我吗?
我期望的输出是:
10.7
20.3
30.1
虽然我可以在awk中执行此操作,我只想在perl中执行此操作
输出的顺序对我来说也不是问题。
答案 0 :(得分:5)
$a{$1}++ for ($_=~/(\d+)/g);
这应该是
$a{$_}++ for ($_=~/(\d+)/g);
可以简化为
$a{$_}++ for /\d+/g;
原因是/\d+/g
创建了一个匹配列表,然后由for
迭代。当前元素位于$_
。我想$1
将包含最后一场比赛留在那里的东西,但在这种情况下肯定不是你想要使用的。
答案 1 :(得分:4)
另一种选择是:
$a{$1}++ while ($_=~/(\d+)/g);
这就是我认为您希望代码执行的操作:在匹配发生时循环每个成功匹配。因此,$1
将是您认为的。
只是要清楚区别:
Perl中的单个参数for
循环意味着“为列表的每个元素做一些事情”:
for (@array)
{
#do something to each array element
}
因此,在您的代码中,首先构建了一个匹配列表,并且只有在找到整个匹配列表之后,您才有机会对结果执行某些操作。在构建列表时,$1
已在每个匹配项上重置,但是当您的代码运行时,它被设置为该行的最后一个匹配项。这就是为什么你的结果没有意义。
另一方面,while循环意味着“每次检查这种情况是否为真,并且一直持续到条件为假”。因此,while循环中的代码将在正则表达式的每个匹配上执行,$1
具有该匹配的值。
另一个时间这种差异在Perl中很重要的是文件处理。 for (<FILE>) { ... }
首先将整个文件读入内存,这很浪费。建议改为使用while (<FILE>)
,因为这样你就可以逐行浏览文件,只保留你想要的信息。