迭代已知字符列表

时间:2014-04-12 05:41:43

标签: loops awk gawk

迭代编写程序时已知的字符列表(在本例中,字符为“X”,“Y”,“Z”):

for (i = 1; i <= 3; ++i) {
    c = substr("XYZ", i, 1)
    # do something with the character
}

问题: 是否有更多awk-y方式执行此操作?请注意,这与this question不同,因为我想要的字符迭代不是输入的一部分。

为了把它放在上下文中,我需要计算X,Y和Z在所有线上一行中特定位置的出现次数。输入应仅包含相同长度的X,Y和Zs:

$ cat input.txt
XYXXXYZZYXY
XXXYYYZYYZY
YZZZZYZZXZZ
XXZXXYYZXZY

$ foo.awk < input.txt
X 3 2 2 2 2 0 0 0 2 1 0
Y 1 1 0 1 1 4 1 1 2 0 3
Z 0 1 2 1 1 0 3 3 0 3 1

目前这是foo.awk

#!/bin/awk -f
BEGIN {
    FS = ""
}
NR == 1 {
    len = NF
}
{
    for (i = 1; i <= NF; ++i)
        ++profile[$i][i]
}
END {
    for (c = 1; c <= 3; ++c) {
        char = substr("XYZ", c, 1)
        printf "%s", char
        for (i = 1; i <= len; ++i)
            printf " %d", profile[char][i]
        printf "\n"
    }
}

之前我没有使用过awk,所以可能我的整个方法都是完全错误的。

1 个答案:

答案 0 :(得分:3)

你的脚本看起来不错。这是一个版本,说明了风格的一些细微变化:

#!/usr/bin/awk -f
BEGIN {
    FS = ""
    split("XYZ",chars,"")
}
{
    for (i = 1; i <= NF; ++i)
        ++profile[$i,i]
}
END {
    for (c=1;c in chars;c++) {
        printf "%s", chars[c]
        for (i = 1; i <= NF; ++i)
            printf " %d", profile[chars[c],i]
        printf "\n"
    }
}

语句split("XYZ",chars,"")创建一个数组chars,其中包含您的字母。这样,字符可以通过下标来引用。

您的脚本使用多维数组,这是一个GNU扩展。在上面的脚本中,我使用标准awk方法获得相同的结果。 (设置为FS=""也是GNU扩展名。)

最后,for中的外END循环已更改为使用for (c=1;c in chars;c++) ...扫描数组索引。即使您更改chars中的元素数量,这也具有工作的优势。缺点是,除非我们使代码复杂化,否则awk不能保证索引按顺序出现。