合并第一列和第二列;第三列和第四列等带有分隔符

合并第一列和第二列;第三列和第四列等带有分隔符

我有一个包含 61000 列和 173 行的文本文件。我想合并每2列上的数据,即,应合并第1列和第2列,应合并第3列和第4列,应合并第5列和第6列,依此类推。

输入示例(制表符分隔):

Ind Pop scaffold1   X   scaffold1   X.1 scaffold3   X.2 scaffold4   X.3
a   antartica   1   1   1   1   2   2   1   1
b   antartica   1   1   1   1   2   1   1   2
c   antartica   1   1   1   1   2   1   1   1
d   antartica   1   1   1   1   2   1   1   2
e   antartica   1   1   1   1   2   1   1   2
f   arctic  1   1   1   1   2   1   1   1
g   arctic  1   1   1   2   2   1   1   1
h   arctic  1   1   1   1   2   1   1   1
I   arctic  1   1   1   1   2   1   1   1
j   arctic  1   1   1   1   2   1   1   1

所需的输出(制表符分隔):

Ind-Pop scaffold1-X scaffold2-X.1   scaffold3-X.2   scaffold4-X.3
a-antartica 1-1 1-1 2-2 1-1
b-antartica 1-1 1-1 2-1 1-2
c-antartica 1-1 1-1 2-1 1-1
d-antartica 1-1 1-1 2-1 1-2
e-antartica 1-1 1-1 2-1 1-2
f-arctic    1-1 1-1 2-1 1-1
g-arctic    1-1 1-2 2-1 1-1
h-arctic    1-1 1-1 2-1 1-1
I-arctic    1-1 1-1 2-1 1-1
j-arctic    1-1 1-1 2-1 1-1

我尝试使用 R 中 tidyr 包的 unity 函数来完成此操作。我能够使用以下命令一次合并两列:

     unite(df, newcol, c(scaffold1, X), remove=TRUE)

不知道如何对多列执行此操作。

任何 R 或 perl 或 linux 命令行方法将不胜感激!

答案1

sed -E 's/([^\t]+)\t([^\t]+)/\1-\2/g'

解释

  • sed -E 's/foo/bar/g'sed使用-E扩展正则表达式运行,每行多次替换foo为, 。bar/g
  • ([^\t]+)\t([^\t]+)[^\t]:匹配一个或多个字符长的非制表符+,并将其捕获到一组中([^\t]+)。后面跟着一个制表符,然后是另一个捕获组中的非制表符。
  • \1-\2:将其替换为第一个捕获组,-然后替换为第二个捕获组。本质上,将选项卡替换为 -.

为什么这有效

sed是“贪婪的”,即尝试获取尽可能多的字符。因此,两个捕获组将尝试尽可能长。例如,它将抓取所有a antartica(将其替换为a-antartica)。下次运行搜索时,它已经经过antartica,并在该单词之后的选项卡上再次开始搜索。因此,下一场比赛将是1 1,它将替换为1-1。然后,该模式将对每对列重复。贪心+很重要。如果省略它,该模式将只修改每个选项卡。

答案2

以下是您可以在输入“file.tsv”上使用的一些方法:

$ perl -pe 's/\t/("-",$&)[$|--]/ge'  file.tsv

在这里,我们用破折号替换每个奇数编号的选项卡。

$ sed -e '
    y/\t/\n/
    :a;s/\n/-/;s//\t/;ta
' file.tsv

此 sed 代码将首先将所有制表符更改为换行符,然后逐渐将奇数更改为破折号,甚至将偶数更改为制表符。

$ perl -lpe 's/\t(.*?(?:\t|$))/-$1/g' file.tsv

$ perl -F'\t' -lane '
      push @A, join "-", splice @F,0,2 while @F;
      print join "\t", splice @A;
' file.tsv

$ perl -F'\t' -nae '($,,$")=("\t", "-");
   print map { "@F[2*$_,2*$_+1]" } 0..$#F/2;
' file.tsv

相关内容