Regex [[用AWK编码]]

Regex [[用AWK编码]],regex,awk,Regex,Awk,第一个: 这是我第一次写一个只有AWK的代码 我的背景是BASH思维 我的目标是找出AWK思维,开始写下我自己的AWK代码 因此,我想知道如何编写一个AWK代码: 用替换\n_u_u_(每个\u都是空白) 查找图案并仅打印具有该图案的所有行 将每个分号替换为\nC1\[,并在换行前一行的末尾,用]将其关闭 用下一行补充信息更新前一行 将每行最后一个字的模式与包含国家名称列表的外部文件进行比较 到目前为止,我所做的是(这只涵盖到第三行): 首先,正常的awk代码假定逐行处理。实际上,如果没有其他命

第一个:

  • 这是我第一次写一个只有AWK的代码
  • 我的背景是BASH思维
  • 我的目标是找出AWK思维,开始写下我自己的AWK代码
  • 因此,我想知道如何编写一个AWK代码:

  • 替换
    \n_u_u
    _(每个
    \u
    都是空白)
  • 查找图案并仅打印具有该图案的所有行
  • 将每个分号替换为
    \nC1\[
    ,并在换行前一行的末尾,用
    ]
    将其关闭
  • 用下一行补充信息更新前一行
  • 将每行最后一个字的模式与包含国家名称列表的外部文件进行比较
  • 到目前为止,我所做的是(这只涵盖到第三行):


    首先,正常的awk代码假定逐行处理。实际上,如果没有其他命令行选项,awk将删除所有
    “\n”
    。因此,尝试将
    “\n”
    替换为
    ”;“
    没有多大意义,因为您的代码永远不会看到“\n”

    要将多行合并为一行,可以使用
    printf
    而不是
    print

    /^[AC]\w/ {
                printf "\n%s",$0
                next
            }
    /^\s/ {
                printf " %s",$0
                next
            }
    
    上面的代码表示,当它遇到以
    a
    C
    开头的行,后跟一个单词字符(例如
    U
    1
    i
    )时,然后打印一个新行,后跟该行。当遇到以空格字符(空格或制表符)开头的行时,打印该行而不换行

    当然,这也有一些小问题。例如,它在输出的开头打印一个换行符,而在结尾不打印任何换行符。而且它也不会为以空格开头的行去除前导空格。但我们现在就到此为止

    这回答了您的第一步问题

    但那不是你想要的。您需要的是规范化
    C1
    值。因此,首先让我们编写一段代码,该代码将忽略除
    C1
    值以外的所有内容:

    /^C1/ {print}
    
    好了,现在我们需要处理属于
    C1
    的所有选项卡行,因此我们需要稍微修改一下代码:

    BEGIN {c1_found=0}
    
    /^C1/ {
            c1_found=1
            print
            next
        }
    
    /^\s/ {
            if (c1_found == 1) {
                print "C1 " $0
            }
            next
        }
    
        {
            c1_found = 0
        }
    
    所以。我们创建一个变量
    c1\u found
    来标记我们在
    c1
    块中。我们在BEGIN块中将其初始化为0,并在遇到C1块时将其设置为1。现在,每当我们看到一行以空格开头时,我们检查是否在
    C1
    块中,并通过在前面添加
    “C1”
    来打印该行

    现在我们要处理规范化。这是困难的一点。让我们为此编写一个函数,因为它将在两个地方被调用:

    function normalize (c1_line) {
        split(c1_line,a,"[[]]")
        c1 = a[1]
        names = a[2]
        location = a[3]
    
        split(names,b,";")
    
        for (nam in b) {
            print c1 b[nam] location
        }
    }
    
    此函数首先通过
    [
    ]
    将其输入拆分为三个组成部分。然后它将第二部分拆分为
    。最后,它对名称进行迭代,并为每个名称打印一行

    现在,让我们将其包含到我们的代码中:

    function normalize (c1_line) {
        split(c1_line,a,"[[]]")
        c1 = a[1]
        names = a[2]
        location = a[3]
    
        split(names,b,";")
    
        for (nam in b) {
            print c1 b[nam] location
        }
    }
    
    BEGIN {c1_found=0}
    
    /^C1/ {
            c1_found=1
            normalize($0)
            next
        }
    
    /^\s/ {
            if (c1_found == 1) {
                normalize("C1 " $0)
            }
            next
        }
    
        {
            c1_found = 0
        }
    
    上面的代码生成file1。现在,要生成文件2,最简单的方法是编写另一个脚本,只打印国家名称,然后通过管道将它们传送到
    sort
    uniq
    (或者
    sort-u
    ,如果您的sort可以做到这一点)。然而,如果你坚持用awk来做,你可以(事实上它很简单,可读性也很强)。首先,我们使用关联数组跟踪出现的所有国家:

    function normalize (c1_line) {
        split(c1_line,a,"[[]]")
        c1 = a[1]
        names = a[2]
        location = a[3]
    
        split(names,b,";")
    
        for (nam in b) {
            print c1 b[nam] location
        }
        countries[$NF] = 1
    }
    
    然后我们只需将countries数组打印到一个文件中:

    END {
        for (c in countries) {
            print c >> file2.txt
        }
    }
    
    我会让你来组装完整的程序。但正如您所看到的,awk编程与C或perl或assembly的bash或pascal相比有很大的不同。这更像是在regexp中编程——因为awk有一个内置循环,当找到匹配项时,它会不断扫描输入并执行代码

    例如,以下程序:

    BEGIN {print "starting"}
    /^mango/ {print "ha"}
    /^monkey/ {print $0}
    END {print "done"}
    
    与以下内容完全相同:

    /^monkey/ {print $0}
    END {print "done"}
    BEGIN {print "starting"}
    /^mango/ {print "ha"}
    
    当匹配项是彼此的子字符串时,会有细微的差别。例如,当您想分别从
    /^HELLO/
    触发
    /^HEL/
    时。但一般来说,执行不是自上而下的线性读取


    另外,请注意,awk只有全局变量。因此,请使用好的变量名,以避免在其他地方覆盖其他变量。

    首先,正常的awk代码假定逐行处理。实际上,如果没有其他命令行选项,awk将删除所有
    “\n”
    。因此,尝试将
    “\n”
    替换为
    ”;“
    没有多大意义,因为您的代码永远不会看到“\n”

    要将多行合并为一行,可以使用
    printf
    而不是
    print

    /^[AC]\w/ {
                printf "\n%s",$0
                next
            }
    /^\s/ {
                printf " %s",$0
                next
            }
    
    上面的代码表示,当它遇到以
    a
    C
    开头的行,后跟一个单词字符(例如
    U
    1
    i
    )时,然后打印一个新行,后跟该行。当遇到以空格字符(空格或制表符)开头的行时,打印该行而不换行

    当然,这也有一些小问题。例如,它在输出的开头打印一个换行符,而在结尾不打印任何换行符。而且它也不会为以空格开头的行去除前导空格。但我们现在就到此为止

    这回答了您的第一步问题

    但那不是你想要的。您需要的是规范化
    C1
    值。因此,首先让我们编写一段代码,该代码将忽略除
    C1
    值以外的所有内容:

    /^C1/ {print}
    
    好了,现在我们需要处理属于
    C1
    的所有选项卡行,因此我们需要稍微修改一下代码:

    BEGIN {c1_found=0}
    
    /^C1/ {
            c1_found=1
            print
            next
        }
    
    /^\s/ {
            if (c1_found == 1) {
                print "C1 " $0
            }
            next
        }
    
        {
            c1_found = 0
        }
    
    所以。我们创建一个变量
    c1\u found
    来标记我们在
    c1
    块中。我们在BEGIN块中将其初始化为0,并在遇到C1块时将其设置为1。现在,每当我们看到以空格开头的行时,我们检查是否在
    C1
    块中,并打印它