perl匹配两个文件中字符串的一部分

perl匹配两个文件中字符串的一部分,perl,Perl,我正在使用perl脚本查找两个以制表符分隔的文件中的列之间的匹配。但是对于一列,我只想查找两列中两个字符串之间的部分匹配 它涉及$表2的$行[4]和$表1的$行{d}。 $table2的$row[4]中的值如下所示: “xxxx”。 $table1的$row{d}中的值如下所示: “xxxx.aaa” 如果“.”前面的部分相同,则存在匹配项。如果没有,就没有对手。我不知道如何在我的脚本中实现这一点。这就是我目前所拥有的。我只查找不同列之间的完全匹配。“…”表示对此问题不重要的代码 #! /usr

我正在使用perl脚本查找两个以制表符分隔的文件中的列之间的匹配。但是对于一列,我只想查找两列中两个字符串之间的部分匹配

它涉及$表2的$行[4]和$表1的$行{d}。 $table2的$row[4]中的值如下所示: “xxxx”。 $table1的$row{d}中的值如下所示: “xxxx.aaa”

如果“.”前面的部分相同,则存在匹配项。如果没有,就没有对手。我不知道如何在我的脚本中实现这一点。这就是我目前所拥有的。我只查找不同列之间的完全匹配。“…”表示对此问题不重要的代码

#! /usr/bin/perl
use strict;
use warnings;

use Data::Dumper;
local $Data::Dumper::Useqq = 1;
use Getopt::Long qw(GetOptions);

...

...

chomp( my @header_table2 = split /\t/, <$table2> );

my %lookup;
while(<$table2>){
    chomp;
    my @row = split(/\t/);
    $lookup{ $row[0] }{ $row[1] }{ $row[4] }{ $row[5] }{ $row[6] }{ $row[7] }{ $row[8] } = [ $row[9], $row[10] ];
    } 

my @header = do {
    my $header = <$table1>;
    $header =~ s/\t?\n\z//;
    split /\t/, $header;
   };

print $table3 join ("\t", @header, qw/ name1 name2 /), "\n";


{
no warnings 'uninitialized';
while(<$table1>){
    s/\t?\n\z//;
    my %row;
    @row{@header} = split /\t/;
    print $table3 join ( "\t", @row{@header},
                   @{ $lookup{ $row{a} }{ $row{b} }{ $row{c} }{ $row{d} }{ $row{e} }{ $row{f} }{ $row{g} }
                        // [ "", "" ] }), "\n";
}
}
#/usr/bin/perl
严格使用;
使用警告;
使用数据::转储程序;
本地$Data::Dumper::Useqq=1;
使用Getopt::longqw(GetOptions);
...
...
chomp(my@header_table2=split/\t/,);
我的%lookup;
while(){
咀嚼;
我的@row=split(/\t/);
$lookup{$row[0]}{$row[1]}{$row[4]}{$row[5]}{$row[6]}{$row[7]}{$row[8]}=[$row[9],$row[10];
} 
我的@header=do{
我的$header=;
$header=~s/\t?\n\z/;
拆分/\t/,$header;
};
打印$table3 join(“\t”,@header,qw/name1 name2/),“\n”;
{
没有“未初始化”的警告;
while(){
s/\t?\n\z/;
我的%行;
@行{@header}=split/\t/;
打印$table3 join(“\t”,@row{@header},
@{$lookup{$row{a}}{$row{b}{$row{c}{$row{d}{$row{e}}{$row{f}{$row{g}}
//[“”,“”]}),“\n”;
}
}

由于数组
@row
和哈希
%row
都存在于完全不同的作用域中,因此将出现作用域问题

但是如果您有变量(例如,
$foo
$bar
),并且您想知道
$foo
是否以
$bar
的内容开头,后跟一个点,那么您可以使用如下正则表达式检查:

if ($foo =~ /^$bar\./) {
  # match
} else {
  # no match
}

这看起来像是数据库的工作

下面的解决方案行不通,因为您正在使用九个级别的键(
$row[0]
$row[8]
)构建
%lookup
哈希,并且只使用七个级别(
$row{a}
$row{g}
)访问它,因此您必须在实际情况下进行编辑

我看不出有什么理由对你如此深恶痛绝。通过在相关字段上使用
join
形成的单个键可以正常工作,并且可能会更快一些。我也认为没有理由将
table2
字段提取到数组中,将
table1
字段提取到散列中。在这两种情况下,数组似乎都很好

通过将
表1
中的每一行
@row
复制到数组
@key
,并在构建
$key
字符串之前删除第四个元素的最后一个点和后面的任何内容,我已经解决了您眼前的问题

鉴于您在每条记录末尾的换行之前添加了一个备用制表符的历史记录,我还添加了四条
die
语句,在继续之前验证标题行和列行的大小。您可能需要根据实际数据调整这些值

use strict;
use warnings 'all';

use Data::Dumper;
local $Data::Dumper::Useqq = 1;
use Getopt::Long qw(GetOptions);

use constant TABLE1_COLUMNS => 9;
use constant TABLE2_COLUMNS => 11;

open my $table2, '<', 'table2.txt' or die $!;

my @header_table2 = do {
    my $header = <$table2>;
    $header =~ s/\t?\n\z//;
    split /\t/, $header;
};
die "Incorrect table 2 header count " . scalar @header_table2
    unless @header_table2 == TABLE2_COLUMNS;

my %lookup;

while ( <$table2> ) {
    chomp;
    my @row = split /\t/;
    die "Incorrect table 2 column count " . scalar @row
        unless @row == TABLE2_COLUMNS;

    my $key = do {
        local $" = "\n";
        "@row[0..8]";
    };

    $lookup{ $key } = [ @row[9,10] ];
} 

open my $table1, '<', 'table1.txt' or die $!;

my @header = do {
    my $header = <$table1>;
    $header =~ s/\t?\n\z//;
    split /\t/, $header;
};
die "Incorrect table 1 header count " . scalar @header
    unless @header == TABLE1_COLUMNS;


open my $table3, '>', 'table3.txt' or die $!;


print $table3 join ("\t", @header, qw/ name1 name2 /), "\n";


while ( <$table1> ) {

    s/\t?\n\z//;

    my @row = split /\t/;
    die "Incorrect table 1 column count " . scalar @row
        unless @row == TABLE1_COLUMNS;

    my $key = do {
        my @key = @row;
        $key[3] =~ s/\.[^.]*\z//;
        local $" = "\n";
        "@key";
    };

    my $lookup = $lookup{ $key } // [ "", "" ];

    print $table3 join("\t", @row, @$lookup), "\n";
}
使用严格;
使用“全部”警告;
使用数据::转储程序;
本地$Data::Dumper::Useqq=1;
使用Getopt::longqw(GetOptions);
使用常量表1_列=>9;
使用常数表2_列=>11;
打开我的$table2、'table3.txt'或die$!;
打印$table3 join(“\t”,@header,qw/name1 name2/),“\n”;
而(){
s/\t?\n\z/;
my@row=split/\t/;
die“表1列计数不正确”。标量@行
除非@row==TABLE1\u列;
我的$key=do{
我的@key=@行;
$key[3]=~s/\.[^.]*\z/;
本地$“=”\n”;
“@key”;
};
我的$lookup=$lookup{$key}/[“”,“”];
打印$table3 join(“\t”,@row,@$lookup),“\n”;
}

我理解您的意图,但我的$表1包含大约50列,因此{$lookup{$row{a}}{$row{b}{$row{c}}{$row{d}{$row{e}{$row{f}}{$row{g}}}实际上是指列的名称(在第一行)。因此,我认为您的解决方案在这种情况下不起作用。@user1987607:我看不出您有任何怀疑的理由。您是否尝试过我的代码?除非您显示真实数据,否则我无法提供进一步帮助。我怀疑的原因是表1包含9列,但表2包含50列(不仅仅是“a”到“g”),所以我将表1中的9列与表2中名为“a”、“b”、“c”、“d”、“e”的列进行匹配,但这些列不仅是表2的前9列。@user1987607:不是我的解决方案出了问题,而是您对问题的表述。您是否读过我说的“下面的解决方案行不通,因为。。。"?您没有提供足够的信息,并且您自己的代码不具有自一致性。使用大量嵌套的数据结构而不是简单的复合键不会突然让您的代码正常工作。如果您不能使用我在这里编写的内容,那么我想您必须提出一个新问题,并提供一个完全正常工作的示例以及示例数据同样的问题。