在perl中使用正则表达式匹配创建哈希

时间:2013-01-31 10:51:36

标签: perl

假设我有一个如下文件:

我想将所有十进制数存储在哈希值中。

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中执行此操作

输出的顺序对我来说也不是问题。

2 个答案:

答案 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>),因为这样你就可以逐行浏览文件,只保留你想要的信息。