【问题标题】:Perl grep not returning expected valuePerl grep 未返回预期值
【发布时间】:2012-11-08 22:52:01
【问题描述】:

我有以下代码:

#!/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,但我不知道为什么!

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

【问题讨论】:

    标签: perl


    【解决方案1】:

    问题应该出在这一行:

    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
    

    【讨论】:

    • 感谢您的帮助,但没有骰子。我进行了更改,仍然得到相同的结果。
    • '\t',因为''不解释反斜杠除了`\`和\',传递给正则表达式编译器的字符串实际上是一个文字反斜杠和t,但正则表达式编译器本身处理反斜杠并正确生成制表符正则表达式。但是你是正确的 /\t/ 是更好的形式。
    • 原始数据中确实必须有制表符,否则报告的结果不会出现,但我怀疑 /\s+/ 确实会解决真正的“问题”(尽管它不会保留关于哪些数据在哪个制表符分隔的列中的正确信息)
    • @ysth OP 没有提供有关他的程序试图理解的结构的任何信息,他的程序只计算拆分的(真实)值。
    • 谢谢。上面的答案首先让我到达了那里,所以我给了他答案标记,但是,我感谢您的快速回复和 +1 以进行编辑,这也解决了问题。
    【解决方案2】:

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

    做什么:

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

    表演?

    【讨论】:

    • 我是第二个 +1。我已经有一段时间没有用 perl 编写了,我忘记了这个宝贵的资源。
    【解决方案3】:

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

    尝试按空间分割 往下看

    #!/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
    

    【讨论】:

    • 原始数据中确实必须有标签,否则报告的结果将不会出现。
    • +1 谢谢!由于这是第一个解决我问题症结的帖子,因此我将其标记为答案。问题是额外的空间和改变分割以除以空间工作!
    • split(" ",$_) 最好写成split
    【解决方案4】:

    您的代码works for me。问题可能是输入文件包含一些“隐藏的”空白字段(例如,除了制表符之外的其他空白)。比如

    • A&lt;tab&gt;&lt;space&gt;&lt;CR&gt; 给出两个字段,A&lt;space&gt;&lt;CR&gt;
    • A&lt;tab&gt;B&lt;tab&gt;&lt;CR&gt; 给出三个,AB&lt;CR&gt;(请记住,行尾是输入的一部分!)

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

    scalar(grep /\S/, @fields)
    

    应该这样做。

    【讨论】:

    • +1 帮助我记住chomp!并提供答案:)
    • 改变我的答案,因为最终这对我帮助最大! :) 我在下面发布了一个答案,该答案对我有用。
    【解决方案5】:

    附注:

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

    现在我明白你为什么使用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 返回@fieldstrue 值列表,然后打印你有多少。但有时这不是您想要/期望的:

    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
    

    如果要计算 true 值,请使用此

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

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

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

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

    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 中唯一的 true 值。

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

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

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

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

    知道你在做什么,而不是复制'n'粘贴代码 sn-ps :)

    【讨论】:

    • +1 感谢您努力写出这个令人难以置信的解释。
    【解决方案6】:

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

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

    #!/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"; 
    
    }
    

    【讨论】:

    • 所以您仍然只想计算 true 值吗? :)
    • @memowe -> 是的,我只想要我正在使用的逻辑中的真实值。但是,我非常感谢您提供了出色的解释。它非常清楚,比我使用的原始链接更能帮助我理解所有概念。 SO 用户的慷慨永远让我惊叹!
    猜你喜欢
    • 2013-09-04
    • 2016-02-13
    • 2015-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-04
    • 2020-07-06
    相关资源
    最近更新 更多