Awk 在多行上设置字符串常量的格式,以提高可读性

Awk 在多行上设置字符串常量的格式,以提高可读性,awk,gawk,Awk,Gawk,出于学习目的,我正在为电话号码实现一个小的regexp匹配器。我的目标是可读性,而不是最短的gawk程序: # should match #1234567890 #123-456-7890 #123.456.7890 #(123)456-7890 #(123) 456-7890 BEGIN{ regexp="[0-9]{10},[0-9]{3}[-.][0-9]{3}[.-][0-9]{4},\\([0-9]{3}\\) ?[0-9]{3}-[0-9]{4}" len=spl

出于学习目的,我正在为电话号码实现一个小的regexp匹配器。我的目标是可读性,而不是最短的gawk程序:

# should match
#1234567890
#123-456-7890
#123.456.7890
#(123)456-7890
#(123) 456-7890 

BEGIN{
    regexp="[0-9]{10},[0-9]{3}[-.][0-9]{3}[.-][0-9]{4},\\([0-9]{3}\\) ?[0-9]{3}-[0-9]{4}"
    len=split(regexp,regs,/,/)
}
{for (i=1;i<=len;i++)
    if ($0 ~ regs[i]) print $0
}

在awk中有没有一种简单的方法可以做到这一点?

您可以将regexp存储在变量中,然后将它们连接起来,例如:

awk '{
       COUNTRYCODE="WHATEVER_YOUR_CONTRY_CODE_REGEXP"
       CITY="CITY_REGEXP"
       PHONENR="PHONENR_REGEX"
       THE_WHOLE_THING=COUNTRYCODE CITY PHONENR
       if ($0 ~ THE_WHOLE_THING) { print "BINGO" }
     }'
HTH

开始{
regs[1]=“[0-9]{10}”
regs[2]=“[0-9]{3}[-.][0-9]{3}[.-][0-9]{4}”
regs[3]=“\\([0-9]{3}\\)?[0-9]{3}-[0-9]{4}”
c=3
}
{

对于(i=1;i大家的共识似乎是,没有简单的方法可以在不干扰awk的情况下分割多行字符串?感谢其他的想法,但是让我作为程序员做我不喜欢的工作。因此我提出了这个解决方案,在我看来,它非常接近于一种可执行规范。我使用了d此处记录并处理重新更正以动态创建awk文件:

#!/bin/bash

# numbers that should be matched
read -r -d '' VALID <<'valid'
1234567890
123-456-7890
123.456.7890
(123)456-7890
(123) 456-7890 
valid
# regexp patterns that should match
read -r -d '' PATTERNS <<'patterns'
[0-9]{10}
[0-9]{3}\.[0-9]{3}\.[0-9]{4}
[0-9]{3}-[0-9]{3}-[0-9]{4}
\([0-9]{3}\) ?[0-9]{3}-[0-9]{4}
patterns

gawk --re-interval 'NR==FNR{reg[FNR]=$0;next}
  {for (i in reg) 
    if ($0 ~ reg[i]) print $0}' <(echo "$PATTERNS") <(echo "$VALID")
!/bin/bash
#应该匹配的数字

read-r-d“”有效以下链接可能包含您正在寻找的答案:

它表示,在awk脚本文件或某些Shell的命令行中,awk命令可以与makefile命令相同的方式拆分为几行。只需以反斜杠(
\
)结束该行,awk将在解析时丢弃换行符。将其与字符串的隐式连接(类似于C)结合使用解决办法可能是

BEGIN {
    regexp = "[0-9]{10}," \
             "[0-9]{3}[-.][0-9]{3}[.-][0-9]{4}," \
             "\\([0-9]{3}\\)?[0-9]{3}-[0-9]{4}"
    len = split(regexp, regs, /,/)
}
尽管如此,我还是倾向于将正则表达式直接存储在数组中的解决方案:它更好地反映了语句的意图,并且不会强迫程序员做超出要求的任何工作。此外,不需要
length
函数,因为可以使用foreach语法。应该注意,awk中的数组类似于Java中的映射或Python中的字典,因为它们不将一系列整数索引与值关联。相反,它们将字符串键映射到值。即使使用整数作为键,它们也会隐式转换为字符串。因此,
length
函数并不总是提供的,因为它具有误导性

BEGIN {
    regs[1] = "[0-9]{10}"
    regs[2] = "[0-9]{3}[-.][0-9]{3}[.-][0-9]{4}"
    regs[3] = "\\([0-9]{3}\\)?[0-9]{3}-[0-9]{4}"
}

{
    for (i in regs) {        # i recieves each key added to the regs array
        if ($0 ~ regs[i]) {
            print            # by default `print' prints the whole record
            break            # we can stop finding a regexp
        }
    }
}

请注意,
break
命令过早退出
for
循环。如果每条记录只能打印一次,即使几个正则表达式可以匹配,这是必要的。

我想介绍我最喜欢的这个问题,因为它还没有被提到。我喜欢使用awk的简单字符串附加操作at只是两个术语之间的默认运算符,如典型数学符号中的乘法:

x = x"more stuff"
“更多内容”
附加到
x
并再次将新值设置为
x
。这样您就可以编写

regexp = ""
regexp = regexp"[0-9]{10}"
regexp = regexp"[0-9]{3}[-.][0-9]{3}[.-][0-9]{4}"
regexp = regexp"\\([0-9]{3}\\) ?[0-9]{3}-[0-9]{4}"
要控制代码段之间的其他拆分字符,如我所知的大多数语言和awk之间的换行符,可以使用数组连接和拆分方法从数组生成字符串,并将字符串转换回数组,而不丢失数组的原始结构(例如换行符标记):

使用
regstr=join(regexp,“,”)
添加您使用的拆分。 当然,awk中没有连接函数,但我想它非常简单 要实现,请了解上面的字符串追加操作


我的方法看起来更详细,但有一个优点,即原始数据(本部分中的regexp字符串片段)在每个片段前面都有一个字符串常量。这意味着代码可以通过一个非常简单的算法(甚至一些编辑器快捷方式)生成。

我认为从regs[]数组并将每个模式放入其自己的单元格将更加自我记录,即,
regs[1]=“[0-9]{10}”
…我不确定像
($0~/regex/)和($0~regs[i])
这样的东西会有什么区别。另外,随着regex越来越大,您打算如何管理对它的更改,(很难看到更改的位置,可能在最右边,更重要的是,如果需要逗号字符',',则必须更改分隔符!;-)!祝您好运。您的正则表达式不正确。123.456-789或123-456.789将匹配。但它们不在您的列表中。您可能需要分组。嗨,肯特,谢谢您的关注。我可以使用带有“$0~regs[i]”表单的分组吗?还是我需要使用gensub?+1…尽管我会更改
i Hi@JaypalSingh,很好!值得注意的是长度(数组)是一个扩展(即,它不是在所有现代awk实现中都可用)。
BEGIN {
    regs[1] = "[0-9]{10}"
    regs[2] = "[0-9]{3}[-.][0-9]{3}[.-][0-9]{4}"
    regs[3] = "\\([0-9]{3}\\)?[0-9]{3}-[0-9]{4}"
}

{
    for (i in regs) {        # i recieves each key added to the regs array
        if ($0 ~ regs[i]) {
            print            # by default `print' prints the whole record
            break            # we can stop finding a regexp
        }
    }
}
x = x"more stuff"
regexp = ""
regexp = regexp"[0-9]{10}"
regexp = regexp"[0-9]{3}[-.][0-9]{3}[.-][0-9]{4}"
regexp = regexp"\\([0-9]{3}\\) ?[0-9]{3}-[0-9]{4}"
i = 0
regexp[i++] = "[0-9]{10}"
regexp[i++] = "[0-9]{3}[-.][0-9]{3}[.-][0-9]{4}"
regexp[i++] = "\\([0-9]{3}\\) ?[0-9]{3}-[0-9]{4}"