perl - 用哈希替换字段值

时间:2015-08-17 14:38:10

标签: perl

我需要根据第2列的值替换txt文件列中的值。

我有example_data.txt文件:

Name   Group Value
 ID1    1      1.00
 ID2    1      2.00
 ID3    1      3.00
 ID4    1      4.00
 ID5    2      5.00
 ID6    2      6.00
......................
ID10   10      7.00

example_values.csv文件,以逗号分隔:

1,6.00
2,7.00
......
10,15.00

替换文件应如下所示:

Name   Group Value
 ID1    1      6.00
 ID2    1      6.00
 ID3    1      6.00
 ID4    1      6.00
 ID5    2      7.00
 ID6    2      7.00
......................
ID10   10     15.00

保持字段之间的格式和空格数非常重要。

到目前为止,我已经想出了这个:

#!/usr/bin/perl

use strict;
use warnings;


open(VAL, "<", "example_values.csv") or die $!;
my %hash;
%hash = ( %hash, (split(/,/, $_))) while ( <VAL> );


my $file = '<example_data.txt';
open my $info, $file or die "Could not open $file: $!";
open OUT, ">values_replaced.txt";
my @F = ();
my $k = ();
my %F = ();

while( my $line = <$info>)  {
    if ($line =~ /ID/) {   
        my @fields = split " ";
        s/$F[1]/%hash($k){$F[0]}/; 
        print OUT $line; 
    } else {
        print OUT $line;
    }
}

close(OUT) || die "Couldn't close OUT properly";

我得到的错误信息是:

Use of uninitialized value $F[1] in regexp compilation at perl.pl line 22, <$info> line 18.
Use of uninitialized value $_ in substitution (s///) at perl.pl line 22, <$info> line 18.

但是OUT文件被写入,它只是输入文件的副本。

我感谢任何帮助,我是perl的新手并且现在真的被困住了。

1 个答案:

答案 0 :(得分:4)

看起来这是作业。我将提供一个有效的解决方案和解释,但我希望我不必提醒您,您应该尝试自己解决这个问题,而不是让其他人为您解决。

  • 您拥有use strictuse warnings非常好:)
  • 您正在混合词法文件句柄($fh)和旧式GLOB文件句柄(OUT)。只需使用词汇词汇,always use three-argument open就像open my $fh, '<', 'in.csv';
  • 一样
  • 您用来从VAL读取的构造非常 Perlish ,但正如Borodin所指出的那样,它非常低效,因为它会在每次迭代时合并并构造一个新的哈希。我也不确定你是否可以解释它。如果您想购买花哨的Perl内容,请改用map。它更容易解释它的作用。 ;)
  • close ... || die可能会有效,但您应该使用or。它们是有区别的。 andor不太粘性。这称为优先级。请参阅perlop herehere
  • 您在循环之外声明了从未使用过的变量
    • 始终在最小的词法范围内声明变量
    • 使用有意义的变量名称。 $k@F不是
    • 不要创建两个具有相同名称的变量。可以将%F@F用于Perl,但你肯定会混淆它。
  • while循环中,您splitting为另一个变量,并且您使用$_作为split的输入。但是因为你在循环的头部分配了$line,那就是undef
  • 因为你在一个空格上分裂,你最终会得到很多undef个字段。尝试使用Data::Dumper或更好Data::Printer来输出@fields
  • 中的内容
  • 您正在尝试使用永不填充的变量替换
  • 的内容
  • s///的替换部分语法无效。它将尝试替换为括号中'%hash(){}'警告的文字undef,因为$k为空,而undef$F[0]而发出$_警告
  • 替换也试图在$line
  • 上工作
  • 由于您的目标是替换else,因此您可以跳过$line并在循环后打印close,无论是否已被替换
  • 很高兴use strict; use warnings; use autodie; # always die when open fails # Slurp the mapping. This works on $_ and returns a list # that ends up in the hash. open my $fh_values, "<", "scratch/example_values.txt"; my %group_value_map = map { chomp; split /,/; } (<$fh_values>); close $fh_values; open my $fh_out, '>', '...'; my $file = 'scratch/example_data.txt'; open my $fh_in, '<', $file; while ( my $line = <$fh_in> ) { if ( $line =~ /ID/ ) { # split in " " discards preceeding whitespace and splits # on arbitrary long whitespace sequences (but only if you # use it on the right variable) my @fields = split " ", $line; # This replacement works nicely now, but will break horribly # in case an additional column is added :) $line =~ s/$fields[2]/$group_value_map{$fields[1]}/; } # since we modified $line we don't need an else block that prints the # same value as the last line of the then block print $line; } close $fh_in; close $fh_out; 你的文件句柄,但要保持一致并关闭所有这些文件
Name   Group Value
 ID1    1      6.00
 ID2    1      6.00
 ID3    1      6.00
 ID4    1      6.00
 ID5    2      7.00
 ID6    2      7.00
ID10   10      15.00

<强>输出:

public static void NotifyAboutNewJob(int jobId, bool forceSending = false)
{
        Action<int> notifier = SendAppleNotifications;
        notifier.BeginInvoke(jobId, null, null);
}