C/C++实现字符串模糊匹配


需求:

  准入授权配置文件有时候分了好几个维度进行配置,例如 company|product|sys这种格式的配置:

1.配置 "sina|weibo|pusher" 表示 sina公司weibo产品pusher系统能够准入,而"sina|weibo|sign"不允许准入

2.配置 "sina|*|pusher” 表示sina公司所有产品的pusher系统都能够准入

3.配置 “*|*|pusher” 表示所有公司的所有产品的pusher系统都能够准入

  …

  类似还有很多场景,好了,简单的东西不扯蛋了.

实现:

  面对这个需求我第一时间想的是如何设计模式串,如何快速实现功能,因为我现在写的是一个C服务,所以我首先出现在我脑海的是一大堆strchr(XXX, ‘*'), strchr(XXX, ‘|')等等东西,后面发现这个东西没有必要自己造轮子,有现成的函数可以用,那就是fnmatch.

  google了一下,发现fnmatch的资料并不是很多,大部分还都是讲php函数的,所以没办法,只能自己写写测测了.

#include <iostream>
#include <fnmatch.h>
#include <vector>
using namespace std;
 
int main()
{
  const char* orgin_str = "sina|weibo|pusher";
  char pattern_arr[][20] = {
    {"sina|*|pusher"},
    {"sina|*|*"},
    {"*|weibo|*"},
    //不能被匹配的
    {"sina|pic|*"},
    {"*|*|sign"},
    {"*|weibo|sign"},
    {"*|pic|sign"},
    {"sina|pic|sign"},
 
    {"*|*|*"}
  };
  static int pattern_arr_size = sizeof(pattern_arr) / sizeof(pattern_arr[0]);
 
  vector<char *> vec_str;
  for(int i = 0; i < pattern_arr_size; i ++)
  {
    vec_str.push_back(pattern_arr[i]);
  }
 
  int ret;
  int z = 0;
  while(z < 1){
    for(int i = 0; i < vec_str.size(); i++)
    {   
      ret = fnmatch(vec_str.at(i), orgin_str, FNM_PATHNAME);
      if(FNM_NOMATCH == ret){
        cout<<"sorry I'm failed ["<< vec_str.at(i) <<"]"<<endl;
      }   
    }   
    ++z;  
  }
}

结果:   

  实验一把,结果还不赖,完全满足需求:

  需求满足了,我担心的还有一个问题,那就是性能,注释掉cout输出,将while z语句调至1,000,000,重新编译跑一下:

  time ./fnmatch

看来效率还不错,2.1s 进行了100W次匹配,平均2us一次,性能要求也满足了...

附:上面文章只介绍了在Linux系统下直接调用系统函数fnmatch即可实现,而没有考虑在Windows在的使用。

本人这周看了下Google-glog代码,恰巧发现了一个类似fnmatch的简单实现,因此综合起来提供了一个跨平台的接口。

#ifdef OS_WINDOWS
/* Bits set in the FLAGS argument to `fnmatch'. copy from fnmatch.h(linux) */
#define  FNM_PATHNAME  (1 << 0) /* No wildcard can ever match `/'. */
#define  FNM_NOESCAPE  (1 << 1) /* Backslashes don't quote special chars. */
#define  FNM_PERIOD    (1 << 2) /* Leading `.' is matched only explicitly. */
#define  FNM_NOMATCH    1

#define fnmatch fnmatch_win

/**copy from Google-glog*/
bool SafeFNMatch(const char* pattern,size_t patt_len,const char* str,size_t str_len)
{
  size_t p = 0;
  size_t s = 0;
  while (1)
  {
    if (p == patt_len && s == str_len)
      return true;
    if (p == patt_len)
      return false;
    if (s == str_len)
      return p+1 == patt_len && pattern[p] == '*';
    if (pattern[p] == str[s] || pattern[p] == '?')
    {
      p += 1;
      s += 1;
      continue;
    }
    if (pattern[p] == '*')
    {
      if (p+1 == patt_len) return true;
      do
      {
        if (SafeFNMatch(pattern+(p+1), patt_len-(p+1), str+s, str_len-s))
        {
          return true;
        }
        s += 1;
      } while (s != str_len);

      return false;
    }

    return false;
  }
}

/**注意:Windows平台下尚未实现最后一个参数flags的功能!!!*/
int fnmatch_win(const char *pattern, const char *name, int flags = 0)
{
  if(SafeFNMatch(pattern,strlen(pattern),name,strlen(name)))
    return 0;
  else
    return FNM_NOMATCH;
}

#else
#include <fnmatch.h>
#endif

int main()
{
  const char* orgin_str = "sina|weibo|pusher";
  char pattern_arr[][20] = {
    {"sina|*|pusher"},
    {"sina|*|*"},
    {"*|weibo|*"},
    //不能被匹配的
    {"sina|pic|*"},
    {"*|*|sign"},
    {"*|weibo|sign"},
    {"*|pic|sign"},
    {"sina|pic|sign"},

    {"*|*|*"}
  };
  static int pattern_arr_size = sizeof(pattern_arr) / sizeof(pattern_arr[0]);

  vector<char *> vec_str;
  for(int i = 0; i < pattern_arr_size; i ++)
  {
    vec_str.push_back(pattern_arr[i]);
  }

  std::cout << "Origin Str: " << orgin_str << "\n\n";
  int ret;
  for(int i = 0; i < vec_str.size(); i++)
  {
    ret = fnmatch(vec_str.at(i), orgin_str, FNM_PATHNAME);
    if(ret == FNM_NOMATCH)
    {
      cout<<"sorry, I'm failed: ["<< vec_str.at(i) <<"]\n";
    }
    else
    {
      cout<<"OK, I'm success: ["<< vec_str.at(i) <<"]\n";
    }
  }

  return 0;
}

输出如下:



相关阅读:
Windows8下设置蓝牙配对的操作步骤
详解MySQL的用户密码过期功能
Android开发之Button事件实现与监听方法总结
C# web api返回类型设置为json的两种方法
php实现查看邮件是否已被阅读的方法
jQuery统计上传文件大小的方法
当用户退出点击浏览器后退仍可回到原来页面的解决方案
C#将jpg转换为pdf的方法
JavaScript实现的GBK、UTF8字符串实际长度计算函数
本月底将停售 Win8/Win8.1专业版升级包和介质包
Win8.1更新时提示错误代码为80246010的解决方案
C语言练习题:自由落体的小球简单实例
深入剖析Android系统中Service和IntentService的区别
很酷的HTML5电子书翻页动画特效
快速导航
PHP MySQL HTML CSS JavaScript MSSQL AJAX .NET JSP Linux Mac ASP 服务器 SQL jQuery C# C++ java Android IOS oracle MongoDB SQLite wamp 交通频道 作文范文 火烧赤壁作文500字 心中的星星 习作 描写人物外貌 看重别人的名字 围绕家写一篇作文200字 锻造生命的铁作文500字 县电力局着力解决城区用电质量问题 饱经‘风霜’的老爷爷作文500字 请用我想要的方式来爱我 这就是最后的结局么 教师科学发展观演讲稿 致孩子的一封信作文1600字 懂得,是心中最美 一个人的谎言换来了三个人的生命 悟之语 爷爷家的果园550字 共青团团委干事事迹材料 我的职业梦想演讲稿 读书之瘾 梦想与成功作文150字 你的形象价值百万读后感 土建专业求职信范文 我爱兵的称呼 施蜇存 《唐诗百话》之杂言歌行三首 寂静的气息 阳光的针芒作文3000字 小学五年级作文600字:超越爱情的存在——蓝颜知己 15句正能量励志格言 祝福中温暖的爱_学习雷锋好榜样 人走了,叶落了 我的八音盒作文600字 11月份销售实习工作总结 小学六年级作文550字:随散半 送人归岳阳 难忘的时刻250字 我当队报小主编 想象力丰富(时辉日记) 无声的凋落 2016年元旦演讲稿 不应该属于我的;我倔强的全部接受· 《彼岸花的悲伤》——前提 【原创】池横小说《78----1000》红灯下 救灾面包发霉源于管理制度“发霉” 市地税局成立十周年成效显著 鲁迅作文200字 青春时 邓超演讲稿 在手忙脚乱中学会冷静作文500字 永远有多远,当我不再爱你了 乡镇党委书记抓基层党建工作述职报告

Copyright © 2016 phpStudy |