当特定列中存在特定字符时,拆分特定列的内容

当特定列中存在特定字符时,拆分特定列的内容

我有这个数据选项卡分隔:

ed00011   89    0.12   NA            NA                      No
ed0002s   28    0.11  c3(3.1e-1)     NA                      No
ed0001    22    0.37   NA            186_CR_NCR8_Ot(1.5e-6)  No
ed0002a   596   0.89  c301(9.5e-2)   17_CY7_Ot(0.03)         Yes

我想根据“(...)”(如果存在)拆分第 4 列和第 5 列。如果不存在,则仅具有 NA。例如:

ed00011   89   0.12  NA    NA       NA             NA          No
ed0002s   28   0.11  c3   3.1e-1    NA             NA          No
ed0001    22   0.37  NA    NA      186_CR_NCR8_Ot  1.5e-6      No
ed0002a   596  0.89 c301  9.5e-2   17_CY7_Ot       0.03        Yes

我尝试使用此处建议的命令:使用 awk 分割列 但是,当我没有“(...)”时,我的列就会混乱。有什么建议么?

答案1

awk 'BEGIN { OFS="\t"; }
  {
        if (match($4, /\(.*\)/) > 0) {
                $4=substr($4, 1, RSTART - 1)"\t"substr($4, RSTART + 1, RLENGTH - 2)
        } else {
                $4=$4"\tNA"
        }

        if (match($5, /\(.*\)/) > 0) {
                $5=substr($5, 1, RSTART - 1)"\t"substr($5, RSTART + 1, RLENGTH - 2)
        } else {
                $5=$5"\tNA"
        }
        print
  }' input > output

这里的基本结构是在每一行检查字段 4 或字段 5 是否包含一对匹配的括号。如果是这样,则将该字段替换为两个制表符分隔的值:括号之前的部分和括号内的部分。 RSTART 值是左括号所在的位置,RLENGTH 值包括右括号,因此您会看到一些长度调整。如果这些字段不包含括号,则会附加制表符和“NA”。

重新计算列后,将打印新行。

答案2

BEGIN {
    OFS = FS = "\t"
}

{
    # Shift some fields to the right to make space for new fields after
    # field 4 and 5.
    $8 = $6
    $6 = $5

    # Try matching "(...)" in $4
    if (match($4, "[(][^)]+[)]")) {
        # Succeeded, make $5 the bit inside the parenthesis
        $5 = substr($4, RSTART+1, RLENGTH-2)
        # ... and $4 the bit before the parenthesis.
        $4 = substr($4, 1, RSTART-1)
    } else
        $5 = "NA"

    # Repeat for $6
    if (match($6, "[(][^)]+[)]")) {
        $7 = substr($6, RSTART+1, RLENGTH-2)
        $6 = substr($6, 1, RSTART-1)
    } else
        $7 = "NA"

    print
}

测试:

$ awk -f script.awk file
ed00011   89    0.12    NA      NA      NA      NA      No
ed0002s   28    0.11    c3      3.1e-1  NA      NA      No
ed0001    22    0.37    NA      NA      186_CR_NCR8_Ot  1.5e-6  No
ed0002a   596   0.89    c301    9.5e-2  17_CY7_Ot       0.03    Yes

这些字段在输出中以制表符分隔,但看起来有点奇怪。通过 时效果更好column -t,但实际的选项卡会丢失:

$ awk -f script.awk file | column -t
ed00011  89   0.12  NA    NA      NA              NA      No
ed0002s  28   0.11  c3    3.1e-1  NA              NA      No
ed0001   22   0.37  NA    NA      186_CR_NCR8_Ot  1.5e-6  No
ed0002a  596  0.89  c301  9.5e-2  17_CY7_Ot       0.03    Yes

答案3

可靠的方法

gawk '{
    for(i = 4; i < 6; i++) {
        if($i ~ /\(/) {
            split($i, arr, "[()]")
            $i = arr[1] "\t" arr[2]
        } else {
            $i = $i"\tNA"   
        }
    }
    print
}' OFS='\t' input.txt

不可靠,但正在研究您的样品、方法

sed 's/NA/&\tNA/g; s/(/\t/g; s/)//g' input.txt

该命令执行三个简单步骤:

  1. s/NA/&\tNA/g- 将全部替换为由制表符分隔的NA双精度NA
  2. s/(/\t/g- 将所有左括号替换为制表符。
  3. s/)//g- 删除所有右括号。

它是不可靠的,因为它做了很多假设:括号只能出现在第 4 和 5 列中,NA字符串只能出现在第 4 和 5 列中,第 4 和 5 列中的数字字符串始终具有c3(3.1e-1)相似的格式。因此,如果它们只有唯一c3的、没有括号的部分,则此sed命令将不起作用。

但是,如果您的数据与您的样本严格相同,那么这就能完成工作。

输出

ed00011 89  0.12    NA  NA  NA  NA  No
ed0002s 28  0.11    c3  3.1e-1  NA  NA  No
ed0001  22  0.37    NA  NA  186_CR_NCR8_Ot  1.5e-6  No
ed0002a 596 0.89    c301    9.5e-2  17_CY7_Ot   0.03    Yes

相关内容