【问题标题】:replace strings with lines from another text file by matching patterns通过匹配模式用另一个文本文件中的行替换字符串
【发布时间】:2013-06-23 16:49:09
【问题描述】:

我有一个带有对应键 -> 值的文件:

sort keyFile.txt | head
ENSMUSG00000000001  ENSMUSG00000000001_Gnai3
ENSMUSG00000000003  ENSMUSG00000000003_Pbsn
ENSMUSG00000000003  ENSMUSG00000000003_Pbsn
ENSMUSG00000000028  ENSMUSG00000000028_Cdc45
ENSMUSG00000000028  ENSMUSG00000000028_Cdc45
ENSMUSG00000000028  ENSMUSG00000000028_Cdc45
ENSMUSG00000000031  ENSMUSG00000000031_H19
ENSMUSG00000000031  ENSMUSG00000000031_H19
ENSMUSG00000000031  ENSMUSG00000000031_H19
ENSMUSG00000000031  ENSMUSG00000000031_H19

我想用 temp.txt 中的“值”替换“键”的每个对应关系:

head temp.txt
ENSMUSG00000000001:001  515
ENSMUSG00000000001:002  108
ENSMUSG00000000001:003  64
ENSMUSG00000000001:004  45
ENSMUSG00000000001:005  58
ENSMUSG00000000001:006  63
ENSMUSG00000000001:007  46
ENSMUSG00000000001:008  11
ENSMUSG00000000001:009  13
ENSMUSG00000000003:001  0

结果应该是:

out.txt
ENSMUSG00000000001_Gnai3:001    515
ENSMUSG00000000001_Gnai3:002    108
ENSMUSG00000000001_Gnai3:003    64
ENSMUSG00000000001_Gnai3:004    45
ENSMUSG00000000001_Gnai3:005    58
ENSMUSG00000000001_Gnai3:006    63
ENSMUSG00000000001_Gnai3:007    46
ENSMUSG00000000001_Gnai3:008    11
ENSMUSG00000000001_Gnai3:009    13
ENSMUSG00000000001_Gnai3:001    0

我在this AWK example 之后尝试了一些变体,但如您所见,结果不是我所期望的:

awk 'NR==FNR{a[$1]=$1;next}{$1=a[$1];}1' keyFile.txt temp.txt | head
 515
 108
 64
 45
 58
 63
 46
 11
 13
 0

我的猜测是 temp 的第 1 列与 keyValues 的“完全”第 1 列不匹配。有人可以帮我解决这个问题吗?

也欢迎使用 R/python/sed 解决方案。

【问题讨论】:

    标签: regex perl awk sed


    【解决方案1】:

    像这样使用 awk 命令:

    awk 'NR==FNR {a[$1]=$2;next} {
       split($1, b, ":");
       if (b[1] in a)
           print a[b[1]] ":" b[2], $2;
       else
           print $0;
     }' keyFile.txt temp.txt
    

    【讨论】:

    • 这太棒了@anubhava。我仍在尝试理解该命令的所有内容,但它确实有效。谢谢。
    • +1 ... 只是为了好玩 --> awk 'NR==FNR{a[$1]=$2;next}{split($1, b, ":");print (b[1] in a)?a[b[1]]":"b[2] FS $2:$0}' keyFile.txt temp.txt
    • @JS웃:非常感谢。与往常一样,您有使用三元运算符缩短这些内容的诀窍:P
    • 不客气。只是将单线的真正含义带到桌面上。 :)
    【解决方案2】:

    GNU 代码

    $sed -nr '$!N;/^(.*)\n\1$/!bk;D;:k;s#\S+\s+(\w+)_(\w+)#/^\1/ s/(\\w+)(:\\w+)\\s+(\\w+)/\\1_\2\\2 \\3/p#;P;s/^(.*)\n// ' keyfile.txt|sed -nrf - temp.txt ENSMUSG00000000001_Gnai3:001 515 ENSMUSG00000000001_Gnai3:002 108 ENSMUSG00000000001_Gnai3:003 64 ENSMUSG00000000001_Gnai3:004 45 ENSMUSG00000000001_Gnai3:005 58 ENSMUSG00000000001_Gnai3:006 63 ENSMUSG00000000001_Gnai3:007 46 ENSMUSG00000000001_Gnai3:008 11 ENSMUSG00000000001_Gnai3:009 13 ENSMUSG00000000003_Pbsn:001 0

    【讨论】:

      【解决方案3】:

      另一个 awk 选项

      awk -F: 'NR == FNR{split($0, a, " "); x[a[1]]=a[2]; next}{print x[$1]":"$2}' keyFile.txt temp.txt
      

      【讨论】:

      • 希望你尝试过运行这个。没有给出预期的输出。
      • 您的解决方案无法处理文件的第一行:awk 'NR == FNR {a[$1]=$2;下一个}{FS=":"; print(a[$1]":"$2)}' keyFile.txt temp.txt |头:515 ENSMUSG00000000001_Gnai3:002 108 ENSMUSG00000000001_Gnai3:003 64 ENSMUSG00000000001_Gnai3:004 45 ENSMUSG00000000001_Gnai3:005 58 ENSMUSG00000000001_Gnai3:006 63 ENSMUSG00000000001_Gnai3:007 46 ENSMUSG00000000001_Gnai3:008 11 ENSMUSG00000000001_Gnai3:009 13 ENSMUSG00000000003_Pbsn:001 0 跨度>
      • @anubhava 你的评论速度比我快 :) 我在看到你之前已经发布了。
      • @anubhava 和 fridaymeetssunday,谢谢你的收获。固定的。这是一个可恶的黑客,但我能做到的最好
      【解决方案4】:

      另一个awk版本:

      awk 'NR==FNR{a[$1]=$2;next}
      {sub(/[^:]+/,a[substr($1,1,index($1,":")-1)])}1' keyFile.txt temp.txt
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-23
        • 2021-11-16
        • 2021-04-02
        • 2013-06-17
        • 1970-01-01
        • 1970-01-01
        • 2020-03-25
        • 2019-03-21
        相关资源
        最近更新 更多