匹配File2中File1的字符串,并将File1中的字符串替换为File2中对应的匹配字符串

时间:2012-12-10 12:28:35

标签: perl awk

标题可能令人困惑,这就是我要做的事情:

File1 
12=921:5,895:5,813:5,853:5,978:5,807:5,1200:5,1067:5,827:5

File2 
Tom 12 John 921 Mike 813

Output 
Tom=John:5,Mike:5

file2具有file1中数字的值,我希望匹配并用字符串值替换数字。我用awk中的有限知识尝试了这个,但是无法做到。

任何帮助表示感谢。

2 个答案:

答案 0 :(得分:1)

这是使用GNU awk的一种方式。像:

一样运行
awk -f script.awk file1 file2

script.awk的内容:

BEGIN {
    FS="[ =:,]"
}

FNR==NR {
    a[$1]=$0
    next
}

$2 in a {
    split(a[$2],b)
    for (i=3;i<=NF-1;i+=2) {
        for (j=2;j<=length(b)-1;j+=2) {
            if ($(i+1) == b[j]) {
                line = (line ? line "," : "") $i ":" b[j+1]
            }
        }
    }
    print $1 "=" line
    line = ""
}

结果:

Tom=John:5,Mike:5

或者,这是单行:

awk -F "[ =:,]" 'FNR==NR { a[$1]=$0; next } $2 in a { split(a[$2],b); for (i=3;i<=NF-1;i+=2) for (j=2;j<=length(b)-1;j+=2) if ($(i+1) == b[j]) line = (line ? line "," : "") $i ":" b[j+1]; print $1 "=" line; line = "" }' file1 file2

说明:

  

将awk的字段分隔符更改为空格,等号,冒号或逗号。

     

'FNR == NR {...}'仅适用于参数列表中的第一个文件。

     

因此,当处理file1时,awk会将列'1'添加到数组中,并将整行作为值分配给此数组元素。

     

'next'将简单地跳过处理脚本的其余部分,并阅读下一行输入。

     

当awk读完file1中的输入时,它将继续读取file2。但是,这也会将'FNR'重置为'1',因此awk将跳过处理file2的'FNR == NR'块,因为它不再是真的。

     

因此对于file2:如果可以在上面提到的数组中找到列'2':

     
    

将数组元素的值拆分为另一个数组。这基本上将整个行拆分为file1。

         

现在创建两个循环。

         
      

第一个将循环遍历file2中的所有名称

             

第二个将遍历(第二个)数组中的所有值(这实际上循环遍历file1中的所有字段)。

    
         

现在,当file2中的某个名称后面的值等于file1中的某个键号时,请创建一个类似于以下内容的行构造:'name:number_following_key_number_from_file1'。

         

当在循环期间找到更多名称和值时,四元构造'(......?...:...)'将这些元素添加到行的末尾。这就像一个if语句;如果已经有一行,请在其末尾添加一个逗号,否则不要做任何事情。

         

完成所有循环后,打印出“1”列和该行。然后清空行变量,以便可以再次使用它。

  

HTH。古德勒克。

答案 1 :(得分:0)

以下内容可用作模板:

skrynesaver@busybox ~/ perl -e '$values="12=921:5,895:5,813:5,853:5,978:5,807:5,1200:5,1067:5,827:5";
$data = "Tom 12 John 921 Mike 813";
($line,$values)=split/=/,$values;
@values=split/,/,$values;
$values{$line}="=";
map{$_=~/(\d+)(:\d+)/;$values{$1}="$2";}@values;
if ($data=~/\w+\s$line\s/){
  $data=~s/(\w+)\s(\d+)\s?/$1$values{$2}/g;
}
print "$data\n";
'
Tom=John:5Mike:5
skrynesaver@busybox ~/