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