1

我试图一次有效地匹配多个模式,原则上效果很好:

echo abcdef | awk \
'/abc/ {print "match abc"}
 /def/ {print "match def"}'

此外,我想匹配记录中的所有事件:

echo abcabc | awk \
'function findall(str, re) {
    while(match(str, re)) {
        print "match", re;
        str = substr(str, RSTART+RLENGTH)
    }
}
{
    findall($0, "abc");
}'

现在扩展上面的示例以匹配多个模式,我最终会得到一系列 findall 调用:

findall($0, "abc");
...
findall($0, "def");

问题在于,对于许多不同的模式 (>100),这种方法的性能几乎不如第一个样本。这是有道理的,因为我猜这个模式不会出现在同一个自动机中。

有没有办法稍微加快速度?例如,为多种模式提供“匹配”。我想我可以连接模式(abc|def),但是我会丢失确切匹配的模式的信息。

更新:每一次出现都应该匹配:

abcabc
123
abcxyz

作为输入数据导致2 个匹配记录(给定标准分隔符),但如果与模式“abc”和“xyz”一起使用,则整个数据中有 4 个匹配。这篇文章中的第一个示例至少报告了3 个匹配项,但未能在第一条记录中检测到多次出现的“abc”

4

1 回答 1

2

如何以这种方式做到这一点:

您将模式放在文件中,每个模式放在一行中,而不是放在 awk 函数中。

例如

kent$  cat p.txt
abc
def
foo
xxx

然后你可以加载文件,让 awk 为你做匹配的工作。最后,仅打印出与您的输入字符串匹配的模式:

    echo inputString|awk 'NR==FNR{ps[$0]=0;next;}
{for(p in ps)if(match($0,p))ps[p]++;}
END{for(p in ps) if(ps[p]>0)print p" matched"}' p.txt -

当然,如果需要,您可以将“-”替换为输入文件。

一个小测试:

kent$  echo "abcdefoobarblah"|awk 'NR==FNR{ps[$0]=0;next;}{for(p in ps)if(match($0,p))ps[p]++;}END{for(p in ps) if(ps[p]>0)print p" matched"}' p.txt -
def matched
foo matched
abc matched

所以,模式“xxx”不匹配。只有 def,foo,abc 被打印出来。

请注意,可以优化脚本并使其更短。例如,保存 END{} 块,在第一个 for 循环中执行打印。但是,它向您展示了我的想法如何处理它。

编辑 OP 的评论

乔,我没有在您的问题中看到匹配时间的要求。不过实现起来并不难。请参阅下面的测试以及您的示例文本:

kent$  echo "abcabcabcdefoobarblah"|
awk 'NR==FNR{ps[$0]=0;next;}
{for(p in ps){t=$0;ps[p]=gsub(p,"",t);}}
END{for(p in ps) if(ps[p]>0)print p" matched "ps[p]" time(s)"}' p.txt -

输出:

def matched 1 time(s)
foo matched 1 time(s)
abc matched 3 time(s)
于 2012-02-28T10:49:04.353 回答