如何将一个文件中的所有值替换为另一个文件中的相应名称

时间:2017-01-11 12:22:57

标签: bash perl awk sed

我需要帮助将一个文件(File-1.txt)中的值(数字)替换为另一个文件(File-2)中的值(字符串),其中包含第一列中的值和第二列中的相应名称。这两个文件如下:

文件-1.txt的

(0, ':', [])
(1, ':', [18])
(2, ':', [20, 41])
(3, ':', [18])
(4, ':', [17])
(5, ':', [])
(6, ':', [])

文件-2.txt

1   ALA_A_87
2   THR_A_127
3   GLY_A_128
4   ILE_A_130
5   THR_A_166
6   THR_A_167

预期产出:

(ALA_A_87, ':', [THR_A_127])
(THR_A_127, ':', [ALA_A_87, GLY_A_128, ILE_A_130])
(GLY_A_128, ':', [THR_A_127, 5])
(ILE_A_130, ':', [THR_A_127])
(THR_A_166, ':', [GLY_A_128, THR_A_167])
(THR_A_167, ':', [THR_A_166])

我一直在尝试一些awk代码,但没有运气! awk代码如下:

awk -F, '
    BEGIN {
        subs="ALA_A_87 THR_A_127 GLY_A_128 ILE_A_130 THR_A_166 THR_A_167";
        split( subs, subs_arr );
    }
    NR == 1 { 
        print; 
        next 
    } 
    NR>1{
        for i in {1 2 3 4 5 6 }; {
            $i = subs_arr[ $i++ ];
        }
        print
    }
' File-1.txt

在这里,我提供了代码本身要替换的名称和值,但是如果它可以作为外部文件(File-2.txt)提供,并将File-1.txt中的数字与File-2.txt的第一列,将File-1.txt中的数字替换为File-2.txt中显示的相应名称。帮我解决这个问题。

提前致谢

6 个答案:

答案 0 :(得分:1)

我真的不确定哪些号码应该被替换,但是这个号码取代了[]内的号码,因为它感觉更有趣。您应始终提供预期结果:

$ awk 'NR==FNR { a[$1]=$2; next }
       {
            b=$0;
            gsub(/^.*\[|\].*$/,"",b); 
            if(split(b,c,", ")) 
                for(i in c) 
                    sub(c[i],a[c[i]],b);
            sub(/\[.*\]/,"[" b "]",$0)
       } 1' f2 f1
(0, ':', [])
(1, ':', [GLY_B_235])
(2, ':', [CYS_B_237, SER_D_310])
(3, ':', [GLY_B_235])
(4, ':', [ASP_B_234])
...

修改:为@NeronLeVelu添加了一个版本:

$ awk 'NR==FNR { a[$1]=$2; next }
               { for(i=2;++i<=NF;)
                     sub(/[0-9]+/,a[substr($i,match($i,/[0-9]+/),RLENGTH)],$i)
               } 1' f2 f1
(0, ':', [])
(1, ':', [GLY_B_235])
(2, ':', [CYS_B_237, SER_D_310])
(3, ':', [GLY_B_235])
(4, ':', [ASP_B_234])
...

其他修改:在澄清要求(2 - &gt; 0)之后,这是工作版本:

$ awk 'NR==FNR { a[$1]=$2; next }
               { for(i=0;++i<=NF;)
                     sub(/[0-9]+/,a[substr($i,match($i,/[0-9]+/),RLENGTH)],$i)
               } 1' f2 f1
(, ':', [])
(ALA_A_87, ':', [GLY_B_235])
(THR_A_127, ':', [CYS_B_237, SER_D_310])
(GLY_A_128, ':', [GLY_B_235])
(ILE_A_130, ':', [ASP_B_234])

答案 1 :(得分:1)

如果这是要替换

的名称的file2的第二部分
awk 'FNR==NR{n[$1]=$2;next}
    {
    h=$0;gsub( /\[.*/, "[", h)

    N=$0;gsub( /.*\[|].*/, "", N)
    NsS = split( N, aNs, /,[[:blank:]]*/)

    printf( "%s", h)
    for ( i=1; i<=NsS; i++) printf( "%s%s", (i==1 ? "" : ", "), n[aNs[i]])
    printf( "]\n")
    }
    ' File-2.txt File-1.txt

詹姆斯·布朗的速度与能力的挑战,第二个版本: - )

awk -F '[][[:blank:],]*' '
    FNR==NR{split($0,t,/[[:blank:]]*/);n[t[1]]=t[2];next}
    {
    printf( "%s, %s, [",$1, $2)
    for ( i=3; i<NF; i++) printf( "%s%s", (i==3 ? "" : ", "), n[$i])
    printf( "])\n")
    }
    ' File-2.txt File-1.txt

回复内部&#34;挑战&#34;使用@JamesBrown和最后的OP信息(更改所有F2的数量)

awk -F '[^[:digit:]]*' '
    FNR==NR{n[$1]=$2;next}
    { for ( i=1; i<NF; i++) sub( $i, n[$i]) }
    7
    ' File-2.txt File-1.txt

答案 2 :(得分:1)

我将假设文件未排序,即 File-1.txt 中的 m 行与文件中的 n 行匹配-2.txt ,其中 m 可能不等于 n 。 (在撰写本文时,您尚未提及文件是否已排序。)

解决此问题的一种方法是从 File-2.txt 构建哈希,逐行读取 File-1.txt ,并使用值替换值每行的哈希。

Perl中的示例

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

my $filename1 = 'File-1.txt';
my $filename2 = 'File-2.txt';
my %hash;
my $fh;


open($fh, '<', $filename2) or die "Failed to open $filename2: $!";
while (<$fh>) {
  chomp;
  my ($key, $value) = split;
  $hash{$key} = $value if $value;
}
close $fh;


open($fh, '<', $filename1) or die "Failed to open $filename1: $!";
while (<$fh>) {
  s%^\(\K(\d+)%$hash{$1} // $1%e;
  print;
}
close $fh;

示例输出

(0, ':', [])
(ALA_A_87, ':', [18])
(THR_A_127, ':', [20, 41])
(GLY_A_128, ':', [18])
(ILE_A_130, ':', [17])
(THR_A_166, ':', [])
(THR_A_167, ':', [])
...skipped...
(LEU_D_391, ':', [30])
(ASN_D_399, ':', [8])
(TYR_D_402, ':', [])
(SER_D_404, ':', [8])
(NAO1, ':', [])

如果您想替换所有数字,那就更容易了。替换此替换:

s%^\(\K(\d+)%$hash{$1} // $1%e;

用这个:

s%(\d+)%$hash{$1} // $1%ge;

示例输出

(0, ':', [])
(ALA_A_87, ':', [GLY_B_235])
(THR_A_127, ':', [CYS_B_237, SER_D_310])
(GLY_A_128, ':', [GLY_B_235])
(ILE_A_130, ':', [ASP_B_234])
(THR_A_166, ':', [])
...skipped...
(ARG_D_325, ':', [ASN_B_399, LEU_A_194, VAL_B_396])
(LEU_D_391, ':', [SER_B_310])
(ASN_D_399, ':', [GLY_A_190])
(TYR_D_402, ':', [])
(SER_D_404, ':', [GLY_A_190])
(NAO1, ':', [])

您也可以将此替换应用于整个文件内容。

注意,我使用%作为正则表达式分隔符而不是通常的斜杠,因为否则在替换中不可能使用//运算符。

注意,原始表达

s/^\((\d+)(.*)$/'(' . ( $hash{$1} || $1 ). $2/e;

不是最佳的,因为:

  • (.*)$部分被不必要地处理;
  • (选项;
  • 的帮助下,第一个\K可能保持不变

由于使用 OR 运算符,表达式不太正确。如果$hash中的密钥不存在,则$hash{$1}undef。并且//运算符更合适,因为只有在左侧操作数未定义时才返回右侧操作数。

答案 3 :(得分:1)

在Perl中

直接从%convert的内容构建哈希File-2.txt,并从其键构建正则表达式。然后它检查File-1.txt的每一行是否有一对非空方括号,并将其中的所有数字转换为散列的相应值

use strict;
use warnings 'all';
use autodie;

my %convert = do {
    open my $fh, '<', 'File-2.txt';
    map { split } <$fh>;
};

my $re = join '|', keys %convert;
$re    = qr/\b(?:$re)\b/;

open my $fh, '<', 'File-1.txt';

while ( <$fh> ) {
    s/($re)/$convert{$1}/g;
    print;
}

输出

(0, ':', [])
(ALA_A_87, ':', [GLY_B_235])
(THR_A_127, ':', [CYS_B_237, SER_D_310])
(GLY_A_128, ':', [GLY_B_235])
(ILE_A_130, ':', [ASP_B_234])
(THR_A_166, ':', [])
(THR_A_167, ':', [])
(LYS_A_189, ':', [])
(GLY_A_190, ':', [LEU_D_391])
(ALA_A_191, ':', [])
(GLY_A_192, ':', [ARG_B_304])
(MET_A_193, ':', [ASP_B_241])
(LEU_A_194, ':', [])
(THR_B_200, ':', [SER_B_404])
(MET_B_201, ':', [])
(ASP_B_232, ':', [ASP_D_234])
(ILE_B_233, ':', [ASN_B_399])
(ASP_B_234, ':', [THR_B_200])
(GLY_B_235, ':', [])
(SER_B_236, ':', [])
(CYS_B_237, ':', [LEU_D_311])
(SER_B_238, ':', [GLN_B_305, ASN_B_240])
(ASN_B_240, ':', [GLY_B_235, MET_A_193, GLN_B_305, ARG_B_304])
(ASP_B_241, ':', [GLU_B_398])
(ALA_B_279, ':', [])
(GLU_B_280, ':', [])
(ARG_B_304, ':', [ASP_B_241, GLY_A_128])
(GLN_B_305, ':', [MET_A_193, VAL_B_396])
(ARG_B_308, ':', [ASN_D_399])
(ASP_B_309, ':', [THR_A_167])
(SER_B_310, ':', [])
(LYS_B_313, ':', [SER_B_238])
(LEU_B_391, ':', [ARG_B_308])
(TYR_B_395, ':', [MET_A_193, ARG_D_325, GLU_B_398, GLN_B_305])
(VAL_B_396, ':', [])
(GLU_B_398, ':', [ASP_B_309])
(ASN_B_399, ':', [LYS_A_189])
(SER_B_404, ':', [ARG_B_308])
(GLY_C_192, ':', [])
(ASP_D_234, ':', [ASP_B_309, LEU_D_391])
(ASP_D_309, ':', [])
(SER_D_310, ':', [ARG_D_325, LYS_A_189])
(LEU_D_311, ':', [THR_D_314])
(THR_D_314, ':', [ASN_B_240, GLY_B_235])
(ARG_D_325, ':', [ASN_B_399, LEU_A_194, VAL_B_396])
(LEU_D_391, ':', [SER_B_310])
(ASN_D_399, ':', [GLY_A_190])
(TYR_D_402, ':', [])
(SER_D_404, ':', [GLY_A_190])
(NAO1, ':', [])

答案 4 :(得分:0)

这个awk单行应该有所帮助:

awk 'NR==FNR{a[$1]=$2;next}{FS="[(,]"}sub(/[^,]*/,"("a[$2])+1' f2 f1

输出如下内容:

(, ':', [])
(ALA_A_87, ':', [18])
(THR_A_127, ':', [20, 41])
(GLY_A_128, ':', [18])
(ILE_A_130, ':', [17])
(THR_A_166, ':', [])
(THR_A_167, ':', [])
(LYS_A_189, ':', [])
(GLY_A_190, ':', [45])
(ALA_A_191, ':', [])
(GLY_A_192, ':', [26])
(MET_A_193, ':', [23])
(LEU_A_194, ':', [])
(THR_B_200, ':', [37])
.....

注意第一行,0不存在于file2中,因此()中有空,如果这不是您想要的,请让我知道应该有什么价值。

答案 5 :(得分:0)

这可能适合你(GNU sed):

sed -r 's/^(\S+)\s+(\S+)$/s:\\b\1\\b:\2:g/' file2 | sed -rf - file1

这会将文件2转换为sed脚本,作为文件1的查找。