将结构与一组模式匹配
Posted
技术标签:
【中文标题】将结构与一组模式匹配【英文标题】:Match a structure against set of patterns 【发布时间】:2013-07-24 21:28:47 【问题描述】:我需要将一个结构与一组模式进行匹配,并对每个匹配项采取一些措施。
模式应该支持通配符,我需要确定哪些模式与传入结构匹配,示例集:
action=new_user email=*
action=del_user email=*
action=* email=*@gmail.com
action=new_user email=*@hotmail.com
可以实时添加/删除这些模式。可能有数千个连接,每个都有自己的模式,我需要通知每个连接我收到了一个匹配的结构。模式不是完全正则表达式,我只需要用通配符 * 匹配一个字符串(简单匹配任意数量的字符)。
当服务器接收到结构 action=new_user email=testuser@gmail.com
的消息(我们称之为消息 A)并且我需要找出模式 1 和 3 与此消息匹配时,我应该对每个匹配的模式执行操作(发送此结构 A到相应的连接)。
如何以最有效的方式做到这一点?我可以迭代这些模式并一一检查,但我正在寻找更有效和线程安全的方法来做到这一点。可能可以对这些模式进行分组以减少检查。有什么建议可以做到吗?
UPD:请注意,我想匹配乘法模式(thousands),而不是固定的“字符串”(实际上是一个结构),反之亦然。换句话说,我想找出适合给定结构 A 的模式。
【问题讨论】:
正则表达式库?概率。最好的。 您能否澄清一下:首先,我看到 4 种模式,我认为 1 + 3 匹配(不是 1+2)。其次,您只需要一个是/否的答案(=至少有一个模式匹配),还是您需要一个答案,例如:模式 x,y 匹配,其余不是?第三,模式的集合是固定的,还是可以是任何集合?第四,您的模式语言是什么:完全匹配每个符号,但匹配 * 的任何字符串?还是更通用的正则表达式? 您的模式支持哪些类型的通配符?如果 * 是唯一的,那么您可以编写简单的循环来验证这种模式。如果您需要正则表达式,请使用正则表达式库。 @PSIAlt:模式 3 不应该也与您给出的示例匹配吗? @Zane 很抱歉这个错误。 1+3 应该匹配。是的,我需要对每个匹配模式采取一些行动(将此结构发送到相应的连接)。编辑帖子以说明这一点。 【参考方案1】:将模式转换为正则表达式,并使用RE2 匹配它们,这是用 C++ 编写的,是最快的之一。
【讨论】:
这可能是问题解决方案的一部分 为了获得更高的速度,您可能需要创建一个正则表达式,例如(pattern1)|(pattern2)|...
匹配后,您可以检索匹配的模式。但是你只会得到其中一个:如果 pattern1 和 pattern2 都匹配,你只会得到 pattern1。
是的,但我需要找到所有匹配的模式并为每个模式采取行动(将数据发送到相应的套接字)【参考方案2】:
实际上,如果我理解正确的话,第四个模式是多余的,因为第一个模式更通用,并且包含了与第四个匹配的每个字符串。只剩下 3 种模式,可以通过这个函数轻松检查:
bool matches(const char* name, const char* email)
return strstr(name, "new_user") || strstr(name, "del_user") || strstr(email, "@gmail.com");
如果您更喜欢解析整个字符串,而不仅仅是匹配 action
和 email
的值,那么下面的函数应该可以解决问题:
bool matches2(const char* str)
bool match = strstr(str, "action=new_user ") || strstr(str, "action=del_user ");
if (!match)
const char* emailPtr = strstr(str, "email=");
if (emailPtr)
match = strstr(emailPtr, "@gmail.com");
return match;
请注意,您作为参数输入的字符串必须使用\0
进行转义。你可以阅读strstr
函数here。
【讨论】:
对不起,我没有提到可以实时添加/删除模式。可能有数千个连接,每个都有自己的模式,我需要通知每个连接我已经收到了这个结构(这是匹配的)。【参考方案3】:此strglobmatch
仅支持*
和?
。
#include <string.h> /* memcmp, index */
char* strfixstr(char *s1, char *needle, int needle_len)
int l1;
if (!needle_len) return (char *) s1;
if (needle_len==1) return index(s1, needle[0]);
l1 = strlen(s1);
while (l1 >= needle_len)
l1--;
if (0==memcmp(s1,needle,needle_len)) return (char *) s1;
s1++;
return 0;
int strglobmatch(char *str, char *glob)
/* Test: strglobmatch("almamxyz","?lmam*??") */
int min;
while (glob[0]!='\0')
if (glob[0]!='*')
if ((glob[0]=='?') ? (str[0]=='\0') : (str[0]!=glob[0])) return 0;
glob++; str++;
else /* a greedy search is adequate here */
min=0;
while (glob[0]=='*' || glob[0]=='?') min+= *glob++=='?';
while (min--!=0) if (*str++=='\0') return 0;
min=0; while (glob[0]!='*' && glob[0]!='?' && glob[0]!='\0') glob++; min++;
if (min==0) return 1; /* glob ends with star */
if (!(str=strfixstr(str, glob-min, min))) return 0;
str+=min;
return str[0]=='\0';
【讨论】:
对不起,我怀疑这种暴力方式是否足以每秒匹配多个模式 先测量再根据直觉判断。如果把strfixstr换成最优子串搜索(如Knuth--Morris--Pratt),strglobmatch的算法实际上是最优的(O(glob_len + str_len)),实现简单快速。 感谢回复,但我应该这样检查每个字符串的许多模式,所以它比O(glob_len + str_len)
重得多【参考方案4】:
如果你想要的只是通配符匹配,那么你可以试试这个算法。关键是检查所有不是通配符的子字符串是否在字符串中。
patterns = ["*@gmail.com", "akalenuk@*", "a*a@*", "ak*@gmail.*", "ak*@hotmail.*", "*@*.ua"]
string = "akalenuk@gmail.com"
preprocessed_patterns = [p.split('*') for p in patterns]
def match(s, pp):
i = 0
for w in pp:
wi = s.find(w, i)
if wi == -1:
return False
i = wi+len(w)
return i == len(s) or pp[-1] == ''
print [match(string, pp) for pp in preprocessed_patterns]
但最好还是使用正则表达式,以防您将来需要的不仅仅是通配符。
【讨论】:
以上是关于将结构与一组模式匹配的主要内容,如果未能解决你的问题,请参考以下文章