正则表达式匹配尽可能多的字符串
Regex match as many of strings as possible
我不知道这是否可行或有意义,但我想做的是 grep
或 awk
匹配多个字符串的文件,但只显示匹配项匹配最多的字符串。
所以我会有这样的文件:
cat,dog,apple,bark,chair
apple,chair,wall
cat,wall
phone,key,bark,nut
cat,dog,key
phone,dog,key
table,key,chair
我想匹配包含大部分这些字符串的一行:cat|dog|table|key|wall
。不一定要包括所有这些,但无论哪一行最匹配,都将其打印出来。
例如,我希望它显示以下输出:
cat,dog,key
因为这是包含正在搜索的大部分字符串的行。
我试过使用:
cat filename \
|egrep -iE 'cat' \
|egrep -iE 'dog' \
|egrep -iE 'table' \
|egrep -iE 'key' \
|egrep -iE 'wall'
但它只会显示显示所有字符串的行,我也试过:
egrep -iE 'cat|dog|table|key|wall' filename
但这会显示与这些字符串中的任何一个匹配的任何行。
正则表达式可以做这样的事情吗?
使用awk
,并为每个匹配的单词增加一个计数器。如果计数器高于最高计数,则保存此行。
awk 'BEGIN {max = 0}
{ count=0;
if (/\bcat\b/) count++;
if (/\bdog\b/) count++;
...
if (count > max) { saved = [=10=]; max = count; }
}
END { print saved; }'
$ awk -F, -v r='^(cat|dog|table|key|wall)$' '{c=0;for (i=1;i<=NF;i++)if ($i~r)c++; if (c>max){max=c;most=[=10=]}} END{print most}' file
cat,dog,key
工作原理
-F,
这会将字段分隔符设置为逗号。
-v r='^(cat|dog|table|key|wall)$'
这会将变量 r
设置为匹配您感兴趣的单词的正则表达式。正则表达式以 ^
开头,以 $
结尾。 这确保只有整个单词匹配。
c=0;for (i=1;i<=NF;i++)if ($i~r)c++
这会将变量 c
设置为当前行的匹配项数。
if (c>max){max=c;most=[=18=]}
如果当前行的匹配数 c
超过了先前的最大值 max
,则更新 max
并将 most
设置为当前行.
END{print most}
当我们读完文件后,打印包含 most
个匹配项的行。
为了让问题更有趣,我创建了两个输入文件:
InFile1 ...
cat|dog|table|key|wall
InFile2 ...
cat,dog,apple,bark,chair
apple,chair,wall
cat,wall phone,key,bark,nut
cat,dog,key
phone,dog,key
table,key,chair
请注意 InFile2 与原来的不同 post
因为它包含两行,每行包含三个匹配项。
因此,第一名有一个 "tie",两者都是
已报告。
此代码...
awk -F, '{if (NR==FNR) r=[=12=]; else {count=0
for (j=1;j<=NF;j++) if ($j ~ r) count++
a[FNR]=count" matching words in "[=12=]
if (max<count) max=count}}
END{for (j=1;j<=FNR;j++) if (1==index(a[j],max)) print a[j]}' \
$InFile1 $InFile2 >$OutFile
... 生成了这个 OutFile ...
3 matching words in cat,dog,key
3 matching words in table,key,dog,banana
丹尼尔·B·马丁
我不知道这是否可行或有意义,但我想做的是 grep
或 awk
匹配多个字符串的文件,但只显示匹配项匹配最多的字符串。
所以我会有这样的文件:
cat,dog,apple,bark,chair
apple,chair,wall
cat,wall
phone,key,bark,nut
cat,dog,key
phone,dog,key
table,key,chair
我想匹配包含大部分这些字符串的一行:cat|dog|table|key|wall
。不一定要包括所有这些,但无论哪一行最匹配,都将其打印出来。
例如,我希望它显示以下输出:
cat,dog,key
因为这是包含正在搜索的大部分字符串的行。
我试过使用:
cat filename \
|egrep -iE 'cat' \
|egrep -iE 'dog' \
|egrep -iE 'table' \
|egrep -iE 'key' \
|egrep -iE 'wall'
但它只会显示显示所有字符串的行,我也试过:
egrep -iE 'cat|dog|table|key|wall' filename
但这会显示与这些字符串中的任何一个匹配的任何行。
正则表达式可以做这样的事情吗?
使用awk
,并为每个匹配的单词增加一个计数器。如果计数器高于最高计数,则保存此行。
awk 'BEGIN {max = 0}
{ count=0;
if (/\bcat\b/) count++;
if (/\bdog\b/) count++;
...
if (count > max) { saved = [=10=]; max = count; }
}
END { print saved; }'
$ awk -F, -v r='^(cat|dog|table|key|wall)$' '{c=0;for (i=1;i<=NF;i++)if ($i~r)c++; if (c>max){max=c;most=[=10=]}} END{print most}' file
cat,dog,key
工作原理
-F,
这会将字段分隔符设置为逗号。
-v r='^(cat|dog|table|key|wall)$'
这会将变量
r
设置为匹配您感兴趣的单词的正则表达式。正则表达式以^
开头,以$
结尾。 这确保只有整个单词匹配。c=0;for (i=1;i<=NF;i++)if ($i~r)c++
这会将变量
c
设置为当前行的匹配项数。if (c>max){max=c;most=[=18=]}
如果当前行的匹配数
c
超过了先前的最大值max
,则更新max
并将most
设置为当前行.END{print most}
当我们读完文件后,打印包含
most
个匹配项的行。
为了让问题更有趣,我创建了两个输入文件:
InFile1 ...
cat|dog|table|key|wall
InFile2 ...
cat,dog,apple,bark,chair
apple,chair,wall
cat,wall phone,key,bark,nut
cat,dog,key
phone,dog,key
table,key,chair
请注意 InFile2 与原来的不同 post 因为它包含两行,每行包含三个匹配项。 因此,第一名有一个 "tie",两者都是 已报告。
此代码...
awk -F, '{if (NR==FNR) r=[=12=]; else {count=0
for (j=1;j<=NF;j++) if ($j ~ r) count++
a[FNR]=count" matching words in "[=12=]
if (max<count) max=count}}
END{for (j=1;j<=FNR;j++) if (1==index(a[j],max)) print a[j]}' \
$InFile1 $InFile2 >$OutFile
... 生成了这个 OutFile ...
3 matching words in cat,dog,key
3 matching words in table,key,dog,banana
丹尼尔·B·马丁