【问题标题】:Parsing data in awk在 awk 中解析数据
【发布时间】:2017-04-07 03:46:57
【问题描述】:

我有这样的基因数据:

MUT1    G_->_A_(het)    44%_(96)___[45%_(49)_/_43%_(47)]    rs1799967_(Gene_file;_1000Genomes;_ClinVarVCF;_dbSNP,MutDB) c.4956G>A   1
MUT1    A_->_G_(homo)   99%_(297)___[99%_(151)_/_99%_(146)] rs206075_(Gene_file;_1000Genomes;_ClinVarVCF;_dbSNP)    c.4563A>G   1
MUT1    G_->_C_(homo)   100%_(259)___[100%_(132)_/_100%_(127)]  COSM4147689_(COSMIC),_COSM4147690_(COSMIC),_rs206076_(Gene_file;_1000Genomes;_ClinVar;_ClinVarVCF;_dbSNP)   c.6513G>C   2
MUT1    A_->_C_(het)    41%_(103)___[42%_(53)_/_40%_(50)]   COSM3753646_(COSMIC),_COSM147663_(COSMIC),_rs144848_(Gene_file;_1000Genomes;_ClinVarVCF;_dbSNP,MutDB)   c.1114A>C   5

我需要解析这些数据并仅提取某种字段。

要求输出是:

MUT1    het 44% rs1799967 c.4956G>A 1
MUT1    homo 99% rs206075c.4563A>G  1
MUT1    homo 100% rs206076 c.6513G>C    2
MUT1    het 41% rs144848 c.1114A>C  5

所以输出应该是 - 所有第一列,仅从第二列 het 或 hom,第三列只有 %,第五列应该仅提取 rs_number - 这始终具有不同的位置和最后一列。

注意:我知道,关于 homo/het 的信息总是在第二列的最后一个字段中。并且 % 总是在第三列的第一个字段上。

我的解决办法是:

awk -v OFS="\t" '{print $1,$5,$6,$9,$10,$11}' zkouska.csv | awk -v OFS="\t" 'NR>1{split($2,arr2,"_"); split($3,arr3,"_"); print $1,arr2[4],arr3[1],$4,$5,$6}' 

但输出是:

BRCA1   (het)   44% rs1799967_(Gene_file;_1000Genomes;_ClinVarVCF;_dbSNP,MutDB) c.4956G>A   1
BRCA1   (homo)  99% rs206075_(Gene_file;_1000Genomes;_ClinVarVCF;_dbSNP)    c.4563A>G   1
BRCA1   (homo)  100%    COSM4147689_(COSMIC),_COSM4147690_(COSMIC),_rs206076_(Gene_file;_1000Genomes;_ClinVar;_ClinVarVCF;_dbSNP)   c.6513G>C   2
BRCA1   (het)   41% COSM3753646_(COSMIC),_COSM147663_(COSMIC),_rs144848_(Gene_file;_1000Genomes;_ClinVarVCF;_dbSNP,MutDB)   c.1114A>C   5
BRCA1   (homo)  100%    COSM148277_(COSMIC),_COSM3755561_(COSMIC),_rs16942_(Gene_file;_1000Genomes;_ClinVarVCF;_dbSNP)  c.3548A>G   5

从第五列提取 rs 仍有问题。删除第二个字段中的引号。输入和输出应该是 TAB 分开的。 解决方案不能只在 awk 中。

【问题讨论】:

  • perl 好吗?你可以使用perl -ne 'print join "\t", /^(\S+)/,/^[^(]+\(\K([^)]+)/,/^[^)]+\)\s+\K(\d+%)/,/(rs\d+)/,/\S+\s+\S+\s*$/g' file,它看起来很复杂,但只是一堆提取的文本串在一起......
  • 文件大小预计会很大吗?近 1000 行,对于此处的字符串操作,bash 可能有方便的技巧,但不适用于更大的文件
  • 我认为不会超过 1000 行。当解析需要一段时间时,这不是问题。
  • @Sundeep 感谢您提供 perl 解决方案。我有一个错误无法识别的字符 \xE2;标记为
  • 你可以使用match()函数来查找匹配模式rs[0-9]+的字符串。

标签: python bash parsing awk sed


【解决方案1】:
$ perl -lne 'print join "\t", /^(\S+)/,/^[^(]+\(\K([^)]+)/,/^[^)]+\)\s+\K(\d+%)/,/(rs\d+)/,/(\S+\s+\S+)\s*$/' file
MUT1    het 44% rs1799967   c.4956G>A   1
MUT1    homo    99% rs206075    c.4563A>G   1
MUT1    homo    100%    rs206076    c.6513G>C   2
MUT1    het 41% rs144848    c.1114A>C   5
  • /^(\S+)/ 从行首提取非空白字符
  • /^[^(]+\(\K([^)]+)/ 提取第一个 () 之间的字符
  • /^[^)]+\)\s+\K(\d+%)/ 在第一个 ) 之后提取数字的第一个匹配项,然后是 %
  • /(rs\d+)/ 提取 rs 后跟数字
  • /(\S+\s+\S+)\s*$/ 提取最后两列


另一种方法是分别处理每个字段,类似于bashawk解决方案

$ perl -lane '
$F[1] =~ s/.*\(|\)//g;
$F[2] =~ s/_.*//;
($F[3]) = $F[3] =~ m/(rs\d+)/;
print join "\t", @F;
' file
MUT1    het 44% rs1799967   c.4956G>A   1
MUT1    homo    99% rs206075    c.4563A>G   1
MUT1    homo    100%    rs206076    c.6513G>C   2
MUT1    het 41% rs144848    c.1114A>C   5

【讨论】:

    【解决方案2】:

    结合使用gsubmatch 可能是可行的方法,这是一个可移植的示例:

    parse.awk

    {
      gsub(/^[^(]+\(|\)/, "", $2)
      gsub(/_.*/, "", $3)
      match($4, /rs[0-9]+/)
      print $1, $2, $3, substr($4, RSTART, RLENGTH), $5, $6
    }
    

    像这样运行它:

    awk -f parse.awk OFS='\t' < infile
    

    输出:

    MUT1    het     44%     rs1799967   c.4956G>A   1
    MUT1    homo    99%     rs206075    c.4563A>G   1
    MUT1    homo    100%    rs206076    c.6513G>C   2
    MUT1    het     41%     rs144848    c.1114A>C   5
    

    【讨论】:

    • 很棒的解决方案而且非常简单 - 很好地使用 gsub 和匹配。非常感谢!
    • 我检查了解决方案,输出中缺少 % 信息。
    • @Thor 谢谢。我接受您的回答 - 因为我更喜欢 awk 解决方案。但是 perl 和 bash 解决方案给了我一些新知识,我很感激 :)
    【解决方案3】:

    我为您的要求发布了纯 bash 逻辑。

    #!/bin/bash
    
    while read col1 col2 col3 col4 col5 col6
    do
        subcol2="${col2#*(}";subcol2=${subcol2%)*}                             # Extracting string within the braces '()' using parameter-expansion              
        [[ $col4 =~ .*rs([[:digit:]]+).* ]] && subcol4="${BASH_REMATCH[1]}"    # RegEx in bash to extract number following the 'rs' string
        printf "%s %s %s %s %s %s\n" "$col1" "$subcol2" "${col3%%_*}" "rs$subcol4" "$col5" "$col6"
    done <file
    

    在运行脚本时,产生的结果为

    $ bash script.sh
    MUT1 het 44% rs1799967 c.4956G>A 1
    MUT1 homo 99% rs206075 c.4563A>G 1
    MUT1 homo 100% rs206076 c.6513G>C 2
    MUT1 het 41% rs144848 c.1114A>C 5
    

    注意:解决方案在较大文件上的执行速度可能会较慢。我仅在您的示例文件上对此进行了测试。

    【讨论】:

    • bash 仍然让我感到惊讶。非常好的和有效的解决方案 - 谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-17
    • 2018-04-13
    • 2012-04-16
    • 1970-01-01
    • 2020-05-01
    • 1970-01-01
    相关资源
    最近更新 更多