awk模式匹配解决方案,允许一个模糊/不匹配

时间:2015-02-03 00:29:55

标签: regex awk grep

我想计算文档中的字符串数量。

如果输入为:

GGTGGTGGTAT
GGTAGTGGTAT
GGTGGTGGTAT
GGTAATGGTAT

我搜索GGTGGTGGT我想找到3场比赛。允许一个歧义。

使用egrep看起来像这样,输出为3。

 egrep -c "GGTGGTGGT|.GTGGTGGT|G.TGGTGGT|GG.GGTGGT|GGT.GTGGT|GGTG.TGGT|GGTGG.GGT|GGTGGT.GT|GGTGGTG.T|GGTGGTGG." input

5 个答案:

答案 0 :(得分:4)

以下是使用bash生成该正则表达式的方法:

$ patt=(GGTGGTGGT)
$ for ((i=0; i<${#patt[0]}; i++)); do 
    patt+=( "${patt[0]:0:i}.${patt[0]:i+1}" )
  done
$ regex=$(IFS='|'; echo "${patt[*]}")
$ echo "$regex"
GGTGGTGGT|.GTGGTGGT|G.TGGTGGT|GG.GGTGGT|GGT.GTGGT|GGTG.TGGT|GGTGG.GGT|GGTGGT.GT|GGTGGTG.T|GGTGGTGG.

然后:

awk -v regex="$regex" '$0 ~ regex' file

或仅使用awk:

awk -v srch=GGTGGTGGT '
    BEGIN {
        regex = srch
        for (i=1; i<=length(srch); i++) 
            regex = regex "|" substr(srch,1,i-1) "." substr(srch, i+1)
    }
    $0 ~ regex
' << END
GGTGGTGGTAT
GGTAGTGGTAT
GGTGGTGGTAT
GGTAATGGTAT
END
GGTGGTGGTAT
GGTAGTGGTAT
GGTGGTGGTAT

答案 1 :(得分:2)

这个awk可执行脚本将创建匹配的模式,然后测试每一行以计算匹配:

#!/usr/bin/awk -f

BEGIN { createPatternArray( pattern, a ) }

{
    for( k in a ) { if( $0 ~ k ) { total++; break } }
}

END { print total }

function createPatternArray( pattern, a,       pLen, i ) {
    a[pattern]
    pLen = length( pattern )
    for(i=1; i<=pLen; i++) {
        a[substr(pattern,1,i-1) "." substr(pattern,i+1)]
    }
    # for( k in a ) { print k }
}

如果它放在像awko这样的文件中(并且是可执行的),那么在数据上运行它就像:

awko -v pattern=GGTGGTGGT data
3

createPatternArray函数使数组中的条目如下:

.GTGGTGGT
G.TGGTGGT
GG.GGTGGT
GGT.GTGGT
GGTG.TGGT
GGTGG.GGT
GGTGGT.GT
GGTGGTG.T
GGTGGTGG.
GGTGGTGGT

对于每一行,将根据数组中的条目测试该行的前缀。如果匹配,则增加totals然后中断(否则会有多个匹配)。在END,打印total

答案 2 :(得分:1)

必要的awk模式与你的egrep解决方案相同:

awk '/GGTGGTGGT|.GTGGTGGT|G.TGGTGGT|GG.GGTGGT|GGT.GTGGT|GGTG.TGGT|GGTGG.GGT|GGTGGT.GT|GGTGGTG.T|GGTGGTGG./{print $0}' input

答案 3 :(得分:1)

这是使用(G)awk和gensub函数

的方法
awk -va="GGTGGTGGT" '
        {for(i=1;i<=length(a);i++)if($0~gensub(/./,".",i,a)){print;next}}' file

输出

GGTGGTGGTAT
GGTAGTGGTAT
GGTGGTGGTAT

如何运作

-va="GGTGGTGGT"

将变量a设置为引号中包含的值(无论您想要什么)

{for(i=1;i<=length(a);i++)

创建一个从1到变量a长度的循环。长度是字符串内的字符数。

if($0~gensub(/./,".",i,a))

我先解释一下gensub 前两个args用文字.交换.(任何字符)。第三个参数是来自参数1的匹配的发生。当我们搜索单个字符时,这将仅通过字符串移动,用.替换每个字符。最终的arg是要编辑的字符串,并使用agensub也会返回字符串,而不是编辑原始字符串。

$0~ 

表示整行包含~

后面的内容

这些都包含在if中,当两个评估结果都将导致

$0~.GTGGTGGT
$0~G.TGGTGGT
$0~GG.GGTGGT
$0~GGT.GTGGT
$0~GGTG.TGGT
$0~GGTGG.GGT
$0~GGTGGT.GT
$0~GGTGGTG.T
$0~GGTGGTGG.

{print;next}

如果其中任何一个匹配,则该行将被打印,并且将跳过所有其他指令并处理下一行。


资源

https://www.gnu.org/software/gawk/manual/html_node/String-Functions.html

答案 4 :(得分:0)

您真正想要的是agrep,它代表近似grep。它的效果非常好,有时甚至比常规grep更快。

您可以找到原始的here
安装就像下载tar球,运行tar -xf <file>,在结果文件夹中导航并运行make

一样简单。

或者当前的版本(可能更肿)here

在您的情况下,您只需:

agrep -1 GGTGGTGGT <file>

-#是您希望允许的不匹配数。原始版本最多支持8个不匹配项。

重要的是要注意,agrep认为“不匹配”是插入,删除或替换。因此,将考虑比模式字符串少一个或多一个字符的匹配,而此处的所有其他答案要求匹配具有相同数量的字符