1

我有以下代码:

#!/usr/bin/perl
# splits.pl

use strict;
use warnings;
use diagnostics;

my $pivotfile = "myPath/Internal_Splits_Pivot.txt";

open PIVOTFILE, $pivotfile or die $!;

while (<PIVOTFILE>) { # loop through each line in file

    next if ($. == 1); # skip first line (contains business segment code)
    next if ($. == 2); # skip second line (contains transaction amount text)

    my @fields = split('\t',$_);  # split fields for line into an array     

    print scalar(grep $_, @fields), "\n"; 

}

鉴于文本文件中的数据是这样的:

    4   G   I   M   N   U   X
    Transaction Amount  Transaction Amount  Transaction Amount  Transaction Amount  Transaction Amount  Transaction Amount  Transaction Amount
0000-13-I21             600         
0001-8V-034BLA              2,172   2,172       
0001-8V-191GYG                  13,125      4,375
0001-9W-GH5B2A  -2,967.09       2,967.09    25.00           

我希望 perl 脚本的输出是:2 3 3 4给定每行中定义的元素的数量。该文件是一个制表符分隔的文本文件,有 8 列。

相反,我得到3 4 3 4了,我不知道为什么!

作为背景,我在 Perl 中使用 Counting array elements作为我开发的基础,因为我试图计算行中的元素数量以了解是否需要跳过该行。

4

6 回答 6

2

问题应该在这一行:

my @fields = split('\t',$_);  # split fields for line into an array

制表符不会被插值。而且您的文件似乎不是仅制表符分隔的,至少在此处如此。我更改了拆分正则表达式以匹配任意空格,在我的机器上运行代码并得到“正确”的结果:

my @fields = split(/\s+/,$_);  # split fields for line into an array

结果:

2
3
3
4
于 2012-11-20T19:27:06.570 回答
2

作为旁注:

作为背景,我在 Perl 中使用 Counting array elements作为我开发的基础,因为我试图计算行中元素的数量以了解是否需要跳过该行。

现在我明白了为什么要使用grep数组元素来计数。当您的数组包含如下未定义的值时,这一点很重要:

my @a;
$a[1] = 42;      # @a contains the list (undef, 42)
say scalar @a;   # 2

或者当您手动删除条目时:

my @a = split /,/ => 'foo,bar';    # @a contains the list ('foo', 'bar')
delete $a[0];                      # @a contains the list (undef, 'bar')
say scalar @a;                     # 2

但在许多情况下,尤其是当您使用数组仅存储列表而不对单个数组元素进行操作时,scalar @a效果非常好

my @a = (1 .. 17, 1 .. 25);        # (1, 2, ..., 17, 1, 2, .., 25)
say scalar @a;                     # 42

重要的是要了解,是什么grep!在你的情况下

print scalar(grep $_, @fields), "\n";

grep返回值的列表,@fields然后打印你有多少。但有时这不是您想要/期望的:

my @things = (17, 42, 'foo', '', 0);  # even '' and 0 are things
say scalar grep $_ => @things         # 3!

因为空字符串和数字 0 在 Perl 中是错误值,所以它们不会被该习语计算在内。因此,如果您想知道数组有多长,只需使用

say scalar @array; # number of array entries

如果要计算真实值,请使用此

say scalar grep $_ => @array; # number of true values

但是如果你想计算定义的值,使用这个

say scalar grep defined($_) => @array; # number of defined values

我很确定您已经从链接页面上的其他答案中知道了这一点。在散列中,情况稍微复杂一些,因为设置某些undef内容与deleteing 不同:

my %h = (a => 0, b => 42, c => 17, d => 666);
$h{c} = undef;   # still there, but undefined
delete $h{d};    # BAM! $h{d} is gone!

当我们尝试计算值时会发生什么?

say scalar grep $_ => values %h;   # 1

因为42%h.

say scalar grep defined $_ => values %h;   # 2

因为 0 被定义,虽然它是假的。

say scalar grep exists $h{$_} => qw(a b c d);   # 3

因为可能存在未定义的值。结论:

知道你在做什么而不是复制'n'粘贴代码片段:)

于 2012-11-20T20:26:39.933 回答
2

我怀疑您在某些地方与制表符混合了空格,并且您的 grep 测试会认为“”为真。

有什么作用:

use Data::Dumper;
$Data::Dumper::Useqq=1;
print Dumper [<PIVOTFILE>];

节目?

于 2012-11-20T19:33:40.060 回答
2

不仅有制表符,还有空格。

尝试按空间分割作品看下面

#!/usr/bin/perl
# splits.pl

use strict;
use warnings;
use diagnostics;



while (<DATA>) { # loop through each line in file

    next if ($. == 1); # skip first line (contains business segment code)
    next if ($. == 2); # skip second line (contains transaction amount text)


    my @fields = split(" ",$_);  # split fields by SPACE     

    print scalar(@fields), "\n"; 

}

__DATA__
    4   G   I   M   N   U   X
    Transaction Amount  Transaction Amount  Transaction Amount  Transaction Amount  Transaction Amount  Transaction Amount  Transaction Amount
0000-13-I21             600         
0001-8V-034BLA              2,172   2,172       
0001-8V-191GYG                  13,125      4,375
0001-9W-GH5B2A  -2,967.09       2,967.09    25.00 

输出

2
3
3
4
于 2012-11-20T19:35:20.113 回答
1

你的代码对我有用。问题可能是输入文件包含一些“隐藏的”空白字段(例如,除了制表符之外的其他空白)。例如

  • A<tab><space><CR>给出两个字段,A并且<space><CR>
  • A<tab>B<tab><CR>给出三个, A, B, <CR>(记住,行尾是输入的一部分!)

我建议您chomp使用您使用的每一行;除此之外,您将不得不从仅限空格的字段中清除数组。例如。

scalar(grep /\S/, @fields)

应该这样做。

于 2012-11-20T19:36:53.507 回答
0

在这个问题上有很多很大的帮助,而且很快!

经过漫长而漫长的学习过程,这是我想出的,效果很好,达到了预期的效果。

#!/usr/bin/perl
# splits.pl

use strict;
use warnings;
use diagnostics;

my $pivotfile = "myPath/Internal_Splits_Pivot.txt";

open PIVOTFILE, $pivotfile or die $!;

while (<PIVOTFILE>) { # loop through each line in file

    next if ($. == 1); # skip first line (contains business segment code)
    next if ($. == 2); # skip second line (contains transaction amount text)

    chomp $_; # clean line of trailing \n and white space

    my @fields = split(/\t/,$_);  # split fields for line into an array     

    print scalar(grep $_, @fields), "\n"; 

}
于 2012-11-20T22:48:21.440 回答