将制表符分隔文件中的逗号分隔列表扩展为单独的行

将制表符分隔文件中的逗号分隔列表扩展为单独的行

我有一个非常相似的问题这个问题,但不知道如何使答案适应我自己的问题。

我有一个制表符分隔文件,第二列包含逗号分隔列表,例如:

TRINITY_DN1_c0_g1   DN1_c0_g1   GO:0000166,GO:0003674,GO:0005488,GO:0005515,GO:0005524,GO:0005575
TRINITY_DN1_c0_g3   DN1_c0_g3   GO:0005829,GO:0006457,GO:0006458,GO:0006950,GO:0008134
TRINITY_DN10_c0_g1  DN10_c0_g1  GO:0050896,GO:0051082,GO:0051084,GO:0051085

我想做到这一点:

TRINITY_DN1_c0_g1   DN1_c0_g1   GO:0000166
TRINITY_DN1_c0_g1   DN1_c0_g1   GO:0003674
TRINITY_DN1_c0_g1   DN1_c0_g1   GO:0005488
TRINITY_DN1_c0_g1   DN1_c0_g1   GO:0005515
TRINITY_DN1_c0_g1   DN1_c0_g1   GO:0005524
TRINITY_DN1_c0_g1   DN1_c0_g1   GO:0005575
TRINITY_DN1_c0_g3   DN1_c0_g3   GO:0005829
TRINITY_DN1_c0_g3   DN1_c0_g3   GO:0006457
TRINITY_DN1_c0_g3   DN1_c0_g3   GO:0006458
TRINITY_DN1_c0_g3   DN1_c0_g3   GO:0006950
TRINITY_DN1_c0_g3   DN1_c0_g3   GO:0008134
TRINITY_DN10_c0_g1  DN10_c0_g1  GO:0050896
TRINITY_DN10_c0_g1  DN10_c0_g1  GO:0051082
TRINITY_DN10_c0_g1  DN10_c0_g1  GO:0051084
TRINITY_DN10_c0_g1  DN10_c0_g1  GO:0051085

第三列中的术语数量可变。我需要为其关联的第一列和第二列各占一行。

如果有任何帮助,上述问题的起始内容是:

perl -lne 'if(/^(.*?: )(.*?)(\W*)$/){print"$1$_$3"for split/, /,$2}'

但我不知道需要更改哪些部分才能解决我的问题!

非常感谢您的帮助。

答案1

这个 awk 命令非常可读:

awk '
  BEGIN {FS = "[,\t]"; OFS = "\t"}
  {for (i=3; i<=NF; i++) print $1, $2, $i}
' file

在 Perl 中,这是

perl -F'[,\t]' -lane 'print join "\t", @F[0,1], $F[$_] for 2..$#F' file
# or
perl -F'[,\t]' -slane 'print @F[0,1], $F[$_] for 2..$#F' -- -,=$'\t' file

如果您不确定是否有实际的制表符:

  • awk:FS = ",|[[:blank:]]+"
  • 珀尔:-F',|\s+'

为了好玩,bash

while IFS= read -r line; do
    prefix=${line%%GO:*}
    IFS=, read -ra gos <<< "${line#$prefix}"
    for go in "${gos[@]}"; do echo "$prefix$go"; done
done < file

这个版本不关心空格和制表符,但它会很多比 perl 或 awk 慢。

答案2

使用-a开关将每行拆分为空格上的 @F 数组。

perl -lane 'print join "\t", @F[0, 1], $_ for split /,/, $F[2]'

答案3

这里的另一个选择nest --explode磨坊主

mlr --nidx --fs tab nest --explode --values --across-records --nested-fs ',' -f 3 file

或使用简写nest说明符

mlr --nidx --fs tab nest --evar ',' -f 3 file

答案4

使用GNU sed它具有 [\n\t] 正则表达式功能,我们可以这样做,如下所示:

sed -n '
  y/,/\n/
  :a
      P; s/\t[^\n\t]*\n/\t/
  ta
'  file

你可以使用珀尔

perl -F'(\t)' -pale '$"="";
  $_ = pop(@F) =~ tr/,/\n/r =~ s/^/@F/mgr;
' file

一种方法是珀尔显示在这里。 $a 标量保存前两个字段,然后在 while 循环中从由于 /c 修饰符而停止的位置开始搜索。

perl -lne '
  my($a) = /^((?:.*?\t){2})/gc;
  print $a, $1 while /\G([^,]+)(?:,|$)/g;
' file

相关内容