我有这种格式的文件:
A,C 0|1 0|2 1|2
我现在需要的是:
A 0|1 0|0 1|0
C 0|0 0|1 0|1
所以,我首先分割线条,这不是问题。
awk 'BEGIN{FS=OFS="\t"}{n=split($1,obs,",");for (i=1;i<=n;i++){$1=obs[i];print}}'
但现在我需要删除第一行中的2并删除第二行中的1,甚至将第二行中的2替换为1。
我希望这是可以理解的。数字指的是A(1)和C(2)。 我的想法是使用gsub并将所有数字替换为零,除了当前行的数字。
但是有两个问题我无法解决:
1.以下不起作用(第2行):
awk 'BEGIN{FS=OFS="\t"}{n=split($1,obs,",");for (i=1;i<=n;i++){$1=obs[i];for(j=2;j<=NF;j++){gsub(/[1-9[^2]]/,0,$j)};print}}'
这不应该匹配所有数字但是2?
2.即使这样可行,我还需要用变量(当前行号)替换正则表达式中的数字。
有关于此的任何想法吗?
编辑: 这可能更复杂: 输入
A,C,G,GA 0|1 0|2 1|2 2|3 4|0
期望的输出:
A 0|1 0|0 1|0 0|0 0|0
C 0|0 0|2 0|1 1|0 0|0
A 0|0 0|0 0|0 0|1 0|0
GA 0|0 0|0 0|0 0|0 1|0
答案 0 :(得分:1)
对于一般情况:
awk '{
n = split($1,a,",")
rest = substr($0, length($1)+1)
for (i=1; i<=n; i++) {
regex = "[0-" i-1 i+1 "-9]"
x = rest
gsub(regex, "0", x)
gsub(i, "1", x)
print a[i], x
}
}' << END
A,C,G,GA 0|1 0|2 1|2 2|3 4|0
END
A 0|1 0|0 1|0 0|0 0|0
C 0|0 0|1 0|1 1|0 0|0
G 0|0 0|0 0|0 0|1 0|0
GA 0|0 0|0 0|0 0|0 1|0
答案 1 :(得分:0)
试试这一行:
awk -F"\t", -v OFS="\t"
'{n=split($1,a,",")}n==2{$1=a[1];t=$0;gsub(/2/,"0",t);print t;
$1=a[2];gsub(/1/,"0");gsub(/2/,"1");print}' file
这只处理X,Y
个案例,即$1
中的一对。
测试,(在我的测试f
中,它是空格分隔的,而不是<tab>
,所以没有-F.. -v OFS...
):
kent$ cat f
A,C 0|1 0|2 1|2
kent$ awk '{n=split($1,a,",")}n==2{$1=a[1];t=$0;gsub(/2/,0,t);print t;$1=a[2];gsub(/1/,"0");gsub(/2/,"1");print}' f
A 0|1 0|0 1|0
C 0|0 0|1 0|1
答案 2 :(得分:0)
假设第二个示例输入的示例输出中的杂散2是错误的(它应该是1),那么问题是转换输入:
A,C,G,GA 0|1 0|2 1|2 2|3 4|0
到所需的输出:
A 0|1 0|0 1|0 0|0 0|0
C 0|0 0|1 0|1 1|0 0|0
A 0|0 0|0 0|0 0|1 0|0
GA 0|0 0|0 0|0 0|0 1|0
结合另一个例子,列表中只有两个项目,后面有3对数字,很明显输出中的列数不固定。
AFAICT,目标是将第一个字段拆分为N个字段,然后为N个字段中的每个字段生成一行输出。当数字不是 n 时,字段 n 的输出行包含0,当数字 n 时,输出行包含1。为简单起见,假设列表中不会有超过9个项目(如果数字可以有两位数,则必须使用更复杂的正则表达式。)
翻译成awk
,即成为:
awk '{ N = split($1, code, ",")
$1 = ""
tail = $0
for (i = 1; i <= N; i++)
{
line = code[i] " " tail
for (j = 1; j <= N; j++)
{
if (j != i)
gsub(j, "0", line)
}
gsub(i, "1", line)
print line
}
}'
除了间距之外,这会从给定输入产生所需的输出。可以通过以下方式“固定”间距(如果需要修复):
awk '{ N = split($1, code, ",")
$1 = ""
tail = $0
for (i = 1; i <= N; i++)
{
line = tail
for (j = 1; j <= N; j++)
{
if (j != i)
gsub(j, "0", line)
}
gsub(i, "1", line)
printf("%-4s %s\n", code[i], line
}
}'
答案 3 :(得分:0)
这是我的“自己的”解决方案,退出类似于Jonathan Leffer的解决方案:
awk 'BEGIN{FS=OFS="\t"}{
line=$0
n=split($1,obs,",")
for (i=1;i<=n;i++){
$0=line
$1=obs[i]
for(j=2;j<=NF;j++){
for(k=1;k<=n;k++){
if(k!=i){
gsub(k,"0",$j)
gsub(i,"1",$j)
}
}
}
print
}
}'