将由“| 字符”分隔的名称分隔为各个对

将由“| 字符”分隔的名称分隔为各个对

我想将同一行中的名称分成单独的对。

TMPRSS2|pp9284 AADAT Sample1
ERG    TMPRSS2|pp9284 Sample2
TMPRSS2|pp9284 ETV1 Sample3
PDE4A   MIA|MIA-RAB4B|RAB4B|RAB4B-EGLN2|EGLN2 Sample4

这应该是

TMPRSS2 AADAT Sample1
pp9284 AADAT Sample1
ERG    TMPRSS2 Sample2
ERG  pp9284 Sample2
TMPRSS2 ETV1 Sample3
pp9284 ETV1 Sample3
PDE4A MIA Sample4
PDE4A MIA-RAB4B Sample4
PDE4A RAB4B Sample4
PDE4A RAB4B-EGLN2 Sample4
PDE4A EGLN2 Sample4

多个名称都在两列中,所以我想要单独的对。我已经为此尝试过 mysql,因为在我有单独的对之后,我想将其与另一个表进行比较。 R 中的 strsplit 仅当多个名称的数量固定时才有效。但它们在每一行中都不同。我可以使用 sed、awk 来做到这一点吗?

还有某些列,其值保持相同,并且基本上同一行中的值保持相同。我应该如何打印这些列。我添加了第三列,其值被复制到新行中。为此,我使用了在 for 循环中打印 $3 也可以将它们打印出来,但不起作用。

答案1

$ awk '{split($1,a,"|"); split($2,b,"|"); for (i in a) {for (j in b) print a[i],b[j];}}' file
TMPRSS2 AADAT
pp9284 AADAT
ERG TMPRSS2
ERG pp9284
TMPRSS2 ETV1
pp9284 ETV1
PDE4A RAB4B-EGLN2
PDE4A EGLN2
PDE4A MIA
PDE4A MIA-RAB4B
PDE4A RAB4B

要同时打印第三个 ( SampleN) 字段,您只需添加$3到循环内的 print 语句即可,即

$ awk '{split($1,a,"|"); split($2,b,"|"); for (i in a) {for (j in b) print a[i],b[j],$3;}}' file
TMPRSS2 AADAT Sample1
pp9284 AADAT Sample1
ERG TMPRSS2 Sample2
ERG pp9284 Sample2
TMPRSS2 ETV1 Sample3
pp9284 ETV1 Sample3
PDE4A RAB4B-EGLN2 Sample4
PDE4A EGLN2 Sample4
PDE4A MIA Sample4
PDE4A MIA-RAB4B Sample4
PDE4A RAB4B Sample4

答案2

使用bash:

# important to use parentheses, not braces, to localize changes to IFS
# the variable is purposefully unquoted
split_pipe() ( IFS='|'; echo $1 )

while read -r first second third; do
  for word1 in $(split_pipe "$first"); do
    for word2 in $(split_pipe "$second"); do
      echo $word1 $word2 $third
    done
  done
done < file

答案3

使用 GNU,sed您可以执行以下操作:

sed -E 's/(\|[^ |]+) /\1| /
        s/(([^|]* )?([^|]*))\|(([^ ]*)(.*))/\1\6\n\2\4/
        /\n/P;D' <infile

...打印...

TMPRSS2 AADAT Sample1
pp9284 AADAT Sample1
ERG    TMPRSS2 Sample2
ERG    pp9284 Sample2
TMPRSS2 ETV1 Sample3
pp9284 ETV1 Sample3
PDE4A   MIA Sample4
PDE4A   MIA-RAB4B Sample4
PDE4A   RAB4B Sample4
PDE4A   RAB4B-EGLN2 Sample4
PDE4A   EGLN2 Sample4

它的工作原理是分割并打印,然后逐个删除多余的\n行字符上的一行内容。该P命令P仅打印\n模式空间中第一个出现的 ewline,因此您可以根据需要轻松地仅打印编辑缓冲区的一部分。

在这种情况下,对于每个不包含空格的管道划分部分,sed将所有位两次放置在编辑缓冲区的任一端。sed将最左端和最右端插入到最左侧管道划分部分的左侧和右侧,并按照该顺序使用 ewline \n,然后将相同的选择放在保留在右侧的所有管道划分部分的任一端-其插入的线的手侧\n。因此,如果模式空间中根本存在 ewline,则sed可以P仅打印左侧的位,然后仅删除模式空间中第一个出现的 ewline 并重试。\nD\n

第一次替换只发生一次 - 它只是将一个管道附加到管道分隔部分的末尾,因此总是有一个管道可以分隔 - 即使是最后一次出现。其余时间,sed进行一次s///替换,P在模式空间中打印第一行,然后D进行相同的删除。当它不能再这样做时,它D就会删除全部模式空间并自动拉入下一个输入行。

可以编写用于执行相同操作的 POSIX BRE:

sed '   s/\(|[^ |]\{1,\}\) /\1| /
        s/^\(\( *[^ |]*  *\)*\([^ |]*\)\)|\(\([^ ]*\)\(.*\)\)/\1\6\
\2\4/;   /\n/P;D' <infile

相关内容