3

可以说我有一个如下文件:

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

hello world 10 20
world 10 10 10 10 hello 20
hello 30 20 10 world 10

我在看这个

这很好用:

> 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 中做到这一点

输出的顺序也不是我关心的问题。

4

2 回答 2

5
$a{$1}++ for ($_=~/(\d+)/g);

这应该是

$a{$_}++ for ($_=~/(\d+)/g);

并且可以简化为

$a{$_}++ for /\d+/g;

这样做的原因是/\d+/g创建了一个匹配列表,然后由 迭代for。当前元素在$_. 我想$1会包含最后一场比赛留下的任何东西,但这绝对不是你想在这种情况下使用的东西。

于 2013-01-31T10:55:34.580 回答
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>)改用,因为那样你会逐行浏览文件并只保留你想要的信息。

于 2013-01-31T11:09:35.027 回答