使用 Perl 将一个制表符分隔文件中的数组元素替换为另一个文件中的哈希值



我想用它们对应的哈希值替换数组中的每个元素。为了更清楚:我有两个文件 1) ref.tab 2) data.tab。参考文件包含如下数据:

A    a
B    b
C    c
D    d

数据文件包含以下数据:

1    apple    red    A
2    orange    orange    B
3    grapes    black    C
4    kiwi    green    D

我现在想用Perl做的是:用ref.tab中的相应值替换data.tab第4列中值的所有实例。

我的代码如下:

#!/usr/bin/perl
use strict;
use warnings;
use diagnostics;
# Define file containing the reference values:
open DFILE, 'ref.tab' or die "Cannot open data file";
# Store each column to an array:
my @caps;
my @small;
while(<DFILE>) {
    my @tmp = split/t/;
    push @caps,$tmp[0];
    push @small,$tmp[1];
}
print join(' ', @caps),"n";
print join(' ', @small),"n";
# convert individual arrays to hashes:
my %replaceid;
@replaceid{@caps} = @small;
print "$_ $replaceid{$_}n" for (keys %replaceid);
# Define the file in which column values are to be replaced:
open SFILE,'output.tab' or die "Cannot open source file";
# Store the required columns in an array:
my @col4;
while(<SFILE>) {
    my @tmp1 = split/t/;
    push @col4,$tmp1[4];
}
for $_ (0..$#col4) {
    if ($_ = keys $replaceid[$col4[$_]]){
        ~s/$_/values $replaceid[$col4[$_]]/g;
    }
}

print "@col4";
close (DFILE);
close (SFILE);
exit;

上述程序会导致此错误:

Use of uninitialized value $tmp1[3] in join or string at replace.pl line 4.

解决方案是什么?

新问题:

现在另一个问题。如果没有相应的替换,我想将该字段留空。知道如何做到这一点吗?那是

参考标签

A   a
B   b
C   c
D   d
F   f

数据标签:

1   apple   red A
2   orange  orange  B
3   grapes  black   C
4   kiwi    green   D
5   melon   yellow  E
6   citron   green  F

期望输出:

1   apple   red a
2   orange  orange  b
3   grapes  black   c
4   kiwi    green   d
5   melon   yellow
6   citron   green  f

我该怎么做?

新发行,2

我现在对AWK解决方案有另一个问题。如果没有匹配项,它确实会将字段留空,但我在第 4 列之后还有其他列;因此,只要找不到匹配项,第五列中的值就会移动到第四列。

1 apple red a sweet
2 orange orange b sour
3 grapes black c sweet
4 kiwi green d sweet
5 melon yellow sweet
6 citron green f sour

在第 5 行:在这里您可以注意到发生了什么;第 5 列中的值将移动到第 4 列,在那里找不到替换。

4 列中的值是 $tmp1[3] ,而不是$tmp1[4]

use strict;
use warnings;
# Define file containing the reference values:
open my $DFILE, '<', 'ref.tab' or die $!;
my %replaceid;
while (<$DFILE>) {
    my ($k, $v) = split;
    $replaceid{$k} = $v;
}
close $DFILE;
# print "$_ $replaceid{$_}n" for (keys %replaceid);
# Define the file in which column values are to be replaced:
open my $SFILE, "<", 'data.tab' or die $!; 
local $" = "t"; #"
while(<$SFILE>) {
  my @tmp1 = split;
  $tmp1[3] = $replaceid{ $tmp1[3] } // qq{"no '$tmp1[3]' key in $replaceid!"};
  # tab separated output of @tmp1 array, thanks to $" var set above
  print "@tmp1n";
}
close $SFILE;

Perl 解决方案:

use strict;
use warnings;
# Create your filehandles
open my $REF , '<', 'ref.tab'  or die $!;
open my $DATA, '<', 'data.tab' or die $!;
my %replaceid;
# Initialize your hashmap from ref file
while (<$REF>) {
    my ($k, $v) = split /s+/;
    $replaceid{$k} = $v;
}
# Read the data file
while(<$DATA>) {
    my @tmp = split /s+/;
    next unless exists $replaceid {$tmp[3]};   # If 4th fld exists in hash
    $tmp[3] = $replaceid{$tmp[3]} or next;     # Replace your current line with hash value
    print join("t", @tmp), "n";              # Print your current line   
}
close $REF;
close $DATA;
<小时 />

AWK解决方案:

awk 'NR==FNR{a[$1]=$2;next}{$4=(a[$4])?a[$4]:""}1' OFS="t" ref.tab data.tab
  • 我们完全读取 ref.tab 文件并将其加载到以第 1 列为键,第 2 列为值的哈希中。
  • 读取 ref.tab 文件后,我们移动到 data.tab 文件并将第 4 列替换为哈希值。

最新更新