【问题标题】:AWK replace all but one digitAWK 替换除一位以外的所有数字
【发布时间】:2014-08-21 20:48:06
【问题描述】:

我有一个这种格式的文件:

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

【问题讨论】:

  • 我无法得到需求的逻辑。您稍后在 $1 上使用了 split 循环遍历它,因此它可以有两个以上的字符串,以逗号分隔。你能解释一下转换的规则是什么吗?更多例子更好?
  • 这是基因型信息。所以人的DNA序列有变化。例如,这个位置可以有字母(核苷酸)A 或 C。每个字段为 0|0 0|1 等等都是一个人。所以我想要做的是拆分这些行,以便 A 有一行,C 有一行。但这意味着:在第一行(核苷酸 A)中,我必须删除所有 2(2|0 2| 1 ...)因为它们指的是C。在第二行中我必须删除那些,因为它们指的是A并将2替换为1,因为这里的第一个(唯一)核苷酸现在是C。
  • 在第二行你没有“删除”1s,你用0替换了1。在第一行,您删除了2s。
  • 好吧...您删除了原始示例....
  • 是的,我把它缩短了,这样更容易看到。是的,我将其替换为 0,这就是我所说的“已删除”对不起。

标签: regex awk split gsub


【解决方案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

【讨论】:

  • 谢谢。我想我必须检查我的文件中是否有超过 8 个项目。
【解决方案2】:

试试这条线:

 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中,是空格分隔的,不是&lt;tab&gt;,所以没有-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

【讨论】:

  • 这对我不起作用。在第一行中只打印第一个字母,在第二行中我还需要将 2s 替换为 1s。这不是问题,但这只有在我知道我必须拆分多少行时才有效,但它可能是 10 种不同的类型。我在上面添加了这个作为示例。
  • @user3793311 我添加了测试和输出。请再次检查代码。
  • @user3793311 如果你想在 $1 的情况下使用X,Y,Z,A,B,C....,也是可以的。那么我们需要循环。
  • 好的,谢谢。我想我会用循环尝试它。我只是认为用 0 替换除这一行中的所有数字之外的所有数字会很好。但是为了快速完成它,我将进行循环。谢谢
【解决方案3】:

这是我的“自己的”解决方案,类似于 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
    }
}'

【讨论】:

  • 您的答案与我的基本相同,除了它执行gsub(i, "1", $j) 映射 N-1 次而不是仅一次(这就足够了)。 gsub() 调用可以移出最里面的 (for (k…)) 循环。干得好。
  • 你是对的!我没有告诉你的是,输入文件中有更多字段。因此,我必须确保 gsub 仅适用于正确的字段。但是感谢您的所有帮助。
【解决方案4】:

假设第二个示例输入的示例输出中的杂散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
       }
     }'

【讨论】:

  • 谢谢,这看起来不错。但是,在看到您的回复之前,我想出了一个非常相似的解决方案(我在没有互联网连接的情况下旅行)。我会在这里发布一个我会尝试你的版本,也许它会更好,因为我的“循环”更多。
猜你喜欢
  • 1970-01-01
  • 2013-05-29
  • 1970-01-01
  • 1970-01-01
  • 2017-08-26
  • 1970-01-01
  • 2019-12-11
  • 2017-04-06
  • 1970-01-01
相关资源
最近更新 更多