-3

测试.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

输出.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”进行比较并附加值。使用此过程我没有得到所需的输出

4

3 回答 3

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
于 2012-08-17T12:42:05.163 回答
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
于 2012-08-17T10:29:25.240 回答
0

让我们首先将数据导入 Perl。您将打开该文件,并将其读入第一个空格的散列拆分中。我不在乎将a, b,c或拆分d为单独的数据,因为它在程序中没有任何区别:

 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 match carbusi_db matches 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子程序。您弄清楚是什么使两个单独的键匹配,并填写详细信息。

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

你也没有指定我是否必须按照读取的顺序打印数组。我可以保留一个键列表,并按顺序排列它们。我没有,因为它会使逻辑复杂化,你没有指定它。


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

于 2012-08-17T13:59:06.310 回答