如何计算多个重叠字符串并获取每行的总出现次数(awk 或其他任何东西)

How do I count multiple overlapping strings and get the total occurences per line (awk or anything else)

我有一个这样的输入文件:

315secondbin    x12121321211332123x
315firstbin 3212212121x
315thirdbin 132221312
316firstbin 121
316secondbin    1212

我想做的是计算每个行计数重叠中存在几个不同字符串(比如“121”和“212”)的实例。所以我的预期输出是:

6
5
0
1
2

所以我稍微修改了另一个线程的一些 awk 以使用 OR 运算符,希望它能计算满足任一条件的所有内容:

{
count = 0
[=12=] = tolower([=12=])
while (length() > 0) {
    m = match([=12=], /212/ || /121/)
    if (m == 0)
         break
    count++
    [=12=] = substr([=12=], m + 1)
}
print count
}

不幸的是,我的输出是这样的:

8
4
0
2
3

但如果我省略了 OR,它就算得上完美了。我做错了什么?

此外,我 运行 文件 ymaz.txt 上的脚本由 运行ning:

 cat ymaz.txt | awk -v "pattern=" -f count3.awk

作为替代方法,我试过这个:

{
count = 0
[=15=] = tolower([=15=])
while (length() > 0) {
    m = match([=15=], /212/)
y = match([=15=], /121/)
    if ((m == 0) && (y == 0))
         break
    count++
    [=15=] = substr([=15=], (m + 1) + (y + 1))
}
print count
}

但我的输出是这样的:

1
1
0
1
1

我做错了什么?我知道我应该理解代码而不是将东西剪切和粘贴在一起,但这就是我目前的技能水平。

顺便说一句,当我没有 OR 时(即我只是搜索 1 个字符串),它工作得很好。

你把事情搞得太复杂了:

{
    count=0
    while ( match([=10=],/121|212/) ) {
        count++
        [=10=]=substr([=10=],RSTART+1)
    }
    print count
}

$ awk -f tst.awk file
6
5
0
1
2

您的根本问题是您将条件与正则表达式混淆了。可以将正则表达式与字符串进行比较以形成条件,当所讨论的字符串为 $0 时,您可以将其省略并仅使用 regexp 作为 shorthand 用于 [=14=] ~ regexp 但在那context 正在测试的内容仍然是一个条件。 match() 的第二个参数是正则表达式,而不是条件。 | 是正则表达式中的 or 运算符,而 || 是条件中的 or 运算符。 /.../ 是正则表达式分隔符。

/foo/ 是正则表达式

[=21=] ~ /foo/是一个条件

/foo/ 在条件上下文中是 shorthand 对于 [=21=] ~ /foo/ 但在任何其他上下文中只是一个正则表达式。

/foo/ || /bar 在条件上下文中是 shorthand for [=25=] ~ /foo/ || [=25=] ~ /bar/ 但是作为 match() awk 的第二个参数实际上假设你打算写:

match([=11=],([=11=] ~ /foo/ || [=11=] ~ /bar/))

即它将针对 foo 或 bar 测试当前记录,如果为真,则该条件的计算结果为 1,然后将 1 赋予 match() 作为第二个参数。

看:

$ echo foo | gawk 'match([=12=],/foo/||/bar/)'        
$ echo foo | gawk '{print /foo/||/bar/}'  
1
$ echo 1foo | gawk 'match([=12=],/foo/||/bar/)'       
1foo

获取 Arnold Robbins 着的 Effective Awk Programming,第 4 版。

Perl 方式:

perl -lpe '$_ = () = m/(?=121|212)/go'

输出:

6
5
0
1
2