匹配键并替换匹配的键的值

时间:2012-08-17 09:20:12

标签: regex perl hash

TEST.TXT

name     a  b  c  d
car      1  2  0  7
tram     7  8  9  5
bus_db   1  6  3  8
cari
busi_db

OUT.txt

name     a  b  c  d
car      1  2  0  7
tram     7  8  9  5
bus_db   1  6  3  8
cari     1  2  0  7
busi_db  1  6  3  8

我有一个文件,如TEST.txt所示,其中几个键没有值。我想匹配没有值的键,并匹配匹配的键的相同值。示例输出如下所示。

编辑:我已经尝试了一个更长的过程来分离带有和不带有不同文件值的键,然后将这些文件与额外的“i”进行比较并附加值。我没有使用此过程获得所需的输出

3 个答案:

答案 0 :(得分:1)

这个程序似乎可以满足您的需求。它期望源数据文件作为命令行上的参数

use strict;
use warnings;

<>;

my %data;
my @keys;

while (<>) {
  my ($key, @values) = split;
  if (@values) {
    $data{$key} = \@values;
    push @keys, $key;
  }
  else {
    (my $newkey = $key) =~ s/i(?![a-z])//i;
    my $values = $data{$newkey};
    $data{$key} = [ @$values ];
    push @keys, $key;
  }
}

my $format = "%-7s%3s%3s%3s%3s\n";
printf $format, qw/ name a  b  c  d /;
for my $key (@keys) {
  printf $format, $key, @{ $data{$key} };
}

<强>输出

name     a  b  c  d
car      1  2  0  7
tram     7  8  9  5
bus_db   1  6  3  8
cari     1  2  0  7
busi_db  1  6  3  8

答案 1 :(得分:0)

这是一个解决方案。这假设空键全部以“i”或“i_db”结尾,并且必须删除i才能获得填充的密钥。如果不是这样,则必须更改行$other_key =~ s/i(?=(_db)?$)//g;以匹配您要查找的内容。另外,我已经将文件I / O留给你了。

use strict; use warnings;

my $header = <DATA>;
#throw away the first field name, as it will be used as the hash key
my (undef,@fields) = (split /\s+/, $header);
my %hash;

#read in the file.
while (<DATA>)
{
    my @row = split /\s+/;
    for (0..$#fields)
    {
        $hash{$row[0]}{$fields[$_]} = $row[$_+1];
    } 
}

#find cases that don't have data and fill them in.
foreach my $line (keys %hash)
{
    foreach (keys %{$hash{$line}})
    {
        unless (defined $hash{$line}{$_})
        {
            my $other_key = $line;
            #Uses a lookahead assertion to match but not delete "_db"
            $other_key =~ s/i(?=(_db)?$)//g;
            if (defined $hash{$other_key}{$_})
            {
                $hash{$line}{$_} = $hash{$other_key}{$_}
            }
        }
    }
}

#Print the output.
print $header;
foreach (keys %hash)
{
    #Uses a hash slice to get all of the values at once.
    print join (" ",$_, @{$hash{$_}}{@fields})."\n";    
}

__END__
name     a  b  c  d
car      1  2  0  7
tram     7  8  9  5
bus_db   1  6  3  8
cari
busi_db

答案 2 :(得分:0)

让我们首先将数据导入Perl。您将打开该文件,并将其读取到第一个空格上的哈希分割中。我不介意将abcd拆分为单独的数据,因为它对程序没有任何影响:

 use strict;
 use warnings;
 use autodie;

 open INPUT, "<", "TEST.txt";
 my %array;
 while my $line (<INPUT>) {
    chomp $line;
    my ($key, $data) = split /\s+/, $line, 2;
    $array{$key} = $value;
 }

这将给我们以下内容:

$array{car} = "1   2   0   7";
$array{tram} = "7   8   9   5";
$array{bus_db} = "1   6   3   8";
$array{cari} = "";
$array{busi_db} = "";

现在,您 没有 的内容解释了:您如何知道空数组成员是否匹配非空数组成员。我如何知道cari 匹配 carbusi_db 匹配 bus_db?是i附加到结尾,但在可能的db后缀之前?他们应该知道他们的其他事情吗?

一旦弄明白,让它们匹配非常简单:

$array{busi_db} = $array{bus_db};

然后,将它们打印出来就很简单了。

 # Go through array and make "null" members match
 while my $key (sort keys %array) {
    if (not $array{$key}) { #Ah! a null array member!
        $matching_key = find_matching_key($key);
        $array{$key} = $array{$matching_key};
    }
 }

# Print them out
while my $key (sort keys %array) {
    print "$key = $array{$key}\n";
}

sub find_matching_key {
   # Here be dragons....
}

问题是find_matching_key子程序。你弄清楚是什么让两个单独的键匹配,并填写详细信息。

顺便说一句,根据您的示例数据,null成员位于非null成员之后。如果这始终是真实条件,则无需将读取循环与 merge 循环分开。不幸的是,你没有说这是否属实。

也没有,你是否指定我是否必须以与读入时相同的顺序打印数组。我可以保留一个键列表,并保持它们的顺序。我没有,因为它会使逻辑复杂化,而你没有指定它。


请注意您的问题排名较低,以及人们将其标记为关闭的事实。这是因为你基本上说:“我有这个问题,为我解决它”。您也没有提供足够的解决方案细节。正如我所说,你谈到了匹配密钥,但没有说明你的意思。