我有一个包含 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