如何计算多个重叠字符串并获取每行的总出现次数(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
我有一个这样的输入文件:
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