AWK正则表达式模式匹配

时间:2014-07-24 11:19:43

标签: regex awk

我有一个文本文件,我需要在一个字段中识别某个模式。我正在使用AWK,并尝试使用match()函数。

要求是我需要查看数字串中是否存在以下模式

??????1?
??????3?
??????5?
??????7?

即我只对最后一个数字感兴趣,但是一个数字是1,3,5或7。

我有一个解决方案,看起来像这样;

    b = match($23, "[0-9][0-9][0-9][0-9][0-9][0-9]1[0-9]")
    c = match($23, "[0-9][0-9][0-9][0-9][0-9][0-9]3[0-9]")
    d = match($23, "[0-9][0-9][0-9][0-9][0-9][0-9]5[0-9]")
    e = match($23, "[0-9][0-9][0-9][0-9][0-9][0-9]7[0-9]")

    if (b || c || d || e)
    {
            print "Found a match" $23
    }

我认为虽然我应该能够像这样简洁地编写正则表达式;

b = match($23, "[0-9]{6}1[0-9]")

但这不起作用。

我错过了什么,或者是我的正则表达技巧(哪些不是很好),真的那么糟糕?

感谢您的期待

2 个答案:

答案 0 :(得分:3)

正则表达式分隔符为/.../,而不是"..."。当你在RE上下文中使用引号时,你要告诉awk存在一个字符串文字中的RE,并且该字符串文字被解析两次,一次是在读取脚本时,然后再一次是在#39 ; s执行使得你的RE规范更加复杂,以适应双重解析。

所以,不要写:

b = match($23, "[0-9]{6}1[0-9]")

写:

b = match($23, /[0-9]{6}1[0-9]/)

代替。

但这不是你的问题。您可能遇到的最大问题是您正在调用不支持RE区间的awk版本,例如{6}。如果您使用的是旧版本的GNU awk,则可以通过添加--re-interval标志来启用该功能:

awk --re-interval '...b = match($23, /[0-9]{6}1[0-9]/)...'

但是,或者你是否正在使用一个不支持RE_intervals的awk,最好的办法是获得更新版本的gawk。

最后,您的整个脚本可以简化为:

awk --re-interval '$23 ~ /[0-9]{6}[1357][0-9]/{print "Found a match", $23}'

如果您愿意,可以将[0-9]更改为[[:digit:]]以获取区域设置。

直到最近才默认支持RE间隔的原因是旧的awk不支持它们,因此在旧的awk中执行时RE为a{2}b的脚本会一直在寻找那些5个字符和gawk并不希望旧脚本在gawk而不是旧awk中执行时悄然破坏。一些发布回来的gawk家伙正确决定默认启用RE间隔,以方便后向兼容。

答案 1 :(得分:0)

这是一个awk解决方案:

awk -v FS="" '$7~/(1|3|5|7)/' file

通过将FS设置为空,每个角色都成为一个字段。然后我们可以测试#7领域。

正如汤姆所说。

awk -v FS="" '$7~/[1357]/' file