【问题标题】:Use Perl like awk to cut fields像 awk 一样使用 Perl 来剪切字段
【发布时间】:2017-11-26 23:31:30
【问题描述】:

我是 perl 新手,我正在尝试像使用 awk 一样从文件中提取数据。我已经从文件中收集了数据并将其存储在数组“array”中。我想抓住唯一的某些列和某些行。例如,我只想选择索引 7 (Q) 并选择三个数字,最终制作一个子程序来平均它们。我还希望能够从 D 中获取日期的单个字段。使用 awk 和 cut 有很简单的方法可以做到这一点,但我很难弄清楚如何用 Perl 做到这一点。

Here is the data.txt file
F gge0001x gge0001y gge0001z
D 12-30-2006 12-30-2006 12-30-2006
T 14:15:20 14:15:55 14:16:27
S a69 a69 a69
B 15.8 16.1 15
M gge06001 gge06001 gge06001
P 30.1 29.6 29.9
Q 20.2 22.3 23.4

我可以把它放到我可以选择我想要的索引的地方,我只是不能剪切字段

Performance Data
Q 20.2 22.4. 23.4

到目前为止,这是我的代码......

use constant;
use strict;
use warnings;
use diagnostics;

my $my_file = 'data.txt';
my @array;

open my $fh, '<', 'data.txt'
        or die "Cant open : ";

printf ("%10s", "Performance Data\n");

while(<$fh>)
{

        if( /\bF|T|B|P|Q|R|H|O|C|K|W|L\b/)
        {
                push @array, $_;

        }
}


my @tab = split(/\s+/, $array[2]);
print $tab[-2], [-3],  "\n";

感谢您的帮助

【问题讨论】:

  • 我有点不清楚。您只想从以Q 开头的行中选择20.222.423.4?那正确吗?还是您也想选择其他行/值? /// 你的所有行都包含 4 个空格分隔的列吗?
  • @PerlDuck 是的,所有行都包含 4 个空格分隔的列。我确实希望从 Q 行中选择 20.2、20.4 和 23.4。我也想选择其他行。例如第 F 行,我只想要第二个字段(gge0001x)。还有其他行具有不同的标准,但是一旦我弄清楚如何在一个示例中执行此操作,我应该能够在整个过程中实现它
  • 一个建议:在学习新工具时,尽量不要模仿你知道的其他工具。虽然这对您有所帮助,但您越早使用新工具及其原生方式和习语越好。例如,这里不需要引用awkcut
  • /\bF|T|B|P|Q|R|H|O|C|K|W|L\b/ 匹配 \bFTB 或 ... 或 L\b。您的意思可能是/\b(?:F|T|B|P|Q|R|H|O|C|K|W|L)\b//^(?:F|T|B|P|Q|R|H|O|C|K|W|L)/(也可以写成/\b[FTBPQRHOCKWL]\b//^[FTBPQRHOCKWL]/

标签: perl


【解决方案1】:

你可以像 oneliner 那样做,例如:

perl -lanE 'print "@F[1,2,3]" if $F[0] eq "Q"' < data.txt

打印

20.2 22.3 23.4

有关开关的含义,请参阅prelrun

或使用脚本 - 一次通过:

use strict;
use warnings;
use feature 'say';
use Data::Dumper;

while(<>) {
    chomp;
    my @cols = split /\s+/;
    if( $cols[0] eq 'Q' ) {
        say "for Q: @cols[1,2,3]";
    }
}

将其用作perl script.pl &lt; data.txt(重定向)。它打印

for Q: 20.2 22.3 23.4

如果你想预先加载整个“矩阵”

use strict;
use warnings;
use feature 'say';
#use Data::Dumper;

my $matrixref;
while(<>) {
    chomp;
    push @$matrixref, [split /\s+/];
}
#say Dumper $matrixref;

for my $lineref (@$matrixref) {
    if( $lineref->[0] eq 'Q' ) {
        say "for Q: @$lineref[1,2,3]";
    }
}

再次使用perl script.pl &lt; data.txt 打印:

for Q: 20.2 22.3 23.4

当然,您可以将while(&lt;&gt;)更改为while(&lt;$fh&gt;)并在内部打开文件......等等。

【讨论】:

    【解决方案2】:

    我认为最简单的方法是在空格字符处分割每一行,然后将它们放入一个散列中,第一列作为键,其余 3 列作为值(在数组 ref 中):

    #!/usr/bin/env perl
    
    use strict;
    use warnings;
    use Data::Dumper;
    
    # hash which gets filled with { 'Q' => [ 20.2, 22.3, 23.4 ], ... }
    my %data;
    
    while( <DATA> ) {
        my @col = split(' ', $_ );
        $data{ $col[0] } = [ $col[1], $col[2], $col[3] ];
    }
    
    print Data::Dumper::Dumper(\%data);
    
    __DATA__
    F gge0001x gge0001y gge0001z
    D 12-30-2006 12-30-2006 12-30-2006
    T 14:15:20 14:15:55 14:16:27
    S a69 a69 a69
    B 15.8 16.1 15
    M gge06001 gge06001 gge06001
    P 30.1 29.6 29.9
    Q 20.2 22.3 23.4
    

    输出(缩减):

    $VAR2 = {
      'B' => [
        '15.8',
        '16.1',
        '15'
      ],
      'D' => [
        '12-30-2006',
        '12-30-2006',
        '12-30-2006'
      ],
      ...
      'Q' => [
        '20.2',
        '22.3',
        '23.4'
      ],
      ...
    };
    

    现在您可以像这样访问Q 的值:

    my $first  = $data{'Q'}[0];
    my $second = $data{'Q'}[1];
    my $third  = $data{'Q'}[2];
    

    这假设您只有 一个 行以 Q 开头。

    【讨论】:

    • my ($first, $second, $third) = @{ $data{Q} };
    • split ' ' 是一种特殊的拆分形式;它不会在空格字符上拆分,它会在任何(或多个)空格上拆分,例如split /\s+/,除了它也忽略任何前导空格。如果您真的想拆分空格字符,请执行split / /
    【解决方案3】:

    您有两个独立的while(&lt;$fh&gt;) 循环这一事实是问题的一部分。第二个 while 循环永远不会运行。我会尝试组合循环作为解决问题的第一步。

    【讨论】:

    • 我删除了第二个循环,并添加了一个新的行。
    猜你喜欢
    • 2021-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-14
    相关资源
    最近更新 更多