将结构与模式集匹配

时间:2013-07-24 21:28:48

标签: c++ performance algorithm

我需要根据一组模式匹配一​​个结构,并为每个匹配采取一些行动。

模式应该支持通配符,我需要确定哪些模式匹配传入结构,例如:

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 :请注意我想要匹配乘法模式()aganst固定“字符串”(实际上是结构),反之亦然。换句话说,我想找到哪些模式适合给定的结构A.

4 个答案:

答案 0 :(得分:1)

将模式转换为正则表达式,并使用RE2匹配它们,{{3}}是用C ++编写的,是最快的模式之一。

答案 1 :(得分:0)

实际上,如果我理解正确,第四种模式是多余的,因为第一种模式更通用,并且包括与第四种模式匹配的每个字符串。这只剩下3种模式,可以通过这个函数轻松检查:

bool matches(const char* name, const char* email)
{
    return strstr(name, "new_user") || strstr(name, "del_user") || strstr(email, "@gmail.com");
}

如果您希望解析整个字符串,而不仅仅是匹配actionemail的值,那么以下函数应该可以解决这个问题:

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

答案 2 :(得分:0)

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';
}

答案 3 :(得分:0)

如果你想要的只是野外卡匹配,那么你可以试试这个算法。关键是要检查所有不是通配符的子串在字符串中是后续的。

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]

但最好仍然使用正则表达式,以防将来需要的东西比野猫更多。