每 2 个值将单个特定列拆分为多个列

每 2 个值将单个特定列拆分为多个列

我有一个包含 5 个字段的基因型文件(第 5 个字段宽度= 200000 个值 [零和一]):

MA,30009,4,4,000010000111101011111000110100000000 .......
ME,30067,3,2,000010000111101011111000110100000000 .......
MI,30032,7,8,000010000111101011111000110100000000 .......

我想将最后一个字段分成多列,每 2 个值 (ncol = 100000)。我希望输出如下:

MA,30009,4,4,00,00,10,00,01,11,10,10,11,11,10,00,11,01,00,00,00,00 .......
ME,30067,3,2,00,00,10,00,01,11,10,10,11,11,10,00,11,01,00,00,00,00 .......
MI,30032,7,8,00,00,10,00,01,11,10,10,11,11,10,00,11,01,00,00,00,00 .......

awk?嘎嘎? sed?

有什么帮助吗?提前致谢

答案1

awk 'BEGIN{FS=OFS=","}{gsub(/../,"&,",$NF)}1' file
  • BEGIN{FS=OFS=","}将字段分隔符设置为,.
  • {gsub(/../,"&,",$NF)}附加,到最后一个字段 ( $NF) 中的每 2 个字符。
  • 1打印结果行。

结果:

MA,30009,4,4,00,00,10,00,01,11,10,10,11,11,10,00,11,01,00,00,00,00,

如果您想删除上述命令生成的尾随逗号,请使用额外的sub函数将其删除:

awk 'BEGIN{FS=OFS=","}{gsub(/../,"&,",$NF);sub(/,$/,"",$NF)}1' file
MA,30009,4,4,00,00,10,00,01,11,10,10,11,11,10,00,11,01,00,00,00,00

答案2

您可以将 Sed 与循环一起使用:

$ sed -E -e :a -e 's/(,[^,]{2})([^,]{1,})$/\1,\2/;ta' file
MA,30009,4,4,00,00,10,00,01,11,10,10,11,11,10,00,11,01,00,00,00,00
ME,30067,3,2,00,00,10,00,01,11,10,10,11,11,10,00,11,01,00,00,00,00
MI,30032,7,8,00,00,10,00,01,11,10,10,11,11,10,00,11,01,00,00,00,00

(我有一种感觉,有一种更简洁的方法可以做到这一点,从头开始$并向后工作 - 但我不能完全确定它)。 (扩展正则表达式)模式-E不是必需的 - 它只是简化了转义。

或者使用 Perl:

$ perl -F, -lne '$last = pop @F; print join ",", @F, $last =~ m/(..)/g' file
MA,30009,4,4,00,00,10,00,01,11,10,10,11,11,10,00,11,01,00,00,00,00
ME,30067,3,2,00,00,10,00,01,11,10,10,11,11,10,00,11,01,00,00,00,00
MI,30032,7,8,00,00,10,00,01,11,10,10,11,11,10,00,11,01,00,00,00,00

答案3

GNU awk 我们将最后一个字段合并到倒数第二个字段中,然后递减字段计数。

gawk -F ',' -v OFS="," '{
  $4 = $4 gensub(/../, ",&", "g", $5)
}NF--' file

用 awk

awk '
  BEGIN { OFS = FS = "," }
  gsub(/../, FS "&", $5) {
    print $1, $2, $3, $4 $5
  }
' file

具有扩展模式的 GNU sed

sed -Ee '
  s/,/\n/4;ta
  :a
    s/\n,/,/;t
    s/..(,..)*$/,&/
  ta
' file

在 Perl 中,我们一次解压第 5 个字段的两个字符。

perl -F, -lape '$_ = join ",", @F[0..3], unpack "(A2)*", $F[4]' file 

使用 Perl 的另一种方法

perl -F, -lane 'print reverse pop(@F) =~ s/(..)/,$1/gr, join ",", @F' file
perl -lpe 's/^.*[^,]\K,(.*)/$1 =~ s|(..)|,$1|gr/e' file

在 rhs 上使用 posix sed (\n) 是象征性的。将其替换为转义换行符)

sed -e '
  s/,/\n/4;h;s/\n.*//;x
  s/.*\n//;s/../,&/g;H;x
  s/\n//
' file

相关内容