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

输出如下:

(0)

相关推荐

  • sql中生成查询的模糊匹配字符串

    if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[f_Sql]') and xtype in (N'FN', N'IF', N'TF')) drop function [dbo].[f_Sql] GO if exists (select * from dbo.sysobjects where id = object_id(N'[序数表]') and OBJECTPROPERTY(id, N'IsUserTa

  • 扩展 Entity Framework支持复杂的过滤条件(多个关键字模糊匹配)

    之前遇到一个棘手的Linq to EF查询的技术问题,现有产品表Product,需要根据多个关键字模糊匹配产品名称, 现将解决方案分享出来. 问题描述 根据需求,我们需要编写如下的SQL语句来查询产品 复制代码 代码如下: select * from dbo.Product where (ProductName like 'Product1%' or ProductName like 'Product2%') 如何将以上的SQL语句转换成EF的写法呢? 方案一 可以使用Union,将以上SQL语

  • 实现按关健字模糊查询,并按匹配度排序的SQL语句

    复制代码 代码如下: IF OBJECT_ID('TB')IS NOT NULL DROP TABLE TB GO CREATE TABLE tb (ID INT IDENTITY(1,1),VALUE NVARCHAR(100)) INSERT tb SELECT N'中国' UNION ALL SELECT N'中国人' UNION ALL SELECT N'中国人民' UNION ALL SELECT N'日本' UNION ALL SELECT N'日本人' UNION ALL SELE

  • python 字符串模糊匹配Fuzzywuzzy的实现

    目录 (1)安装 (2)接口说明 (3)使用 Python提供fuzzywuzzy模块,不仅可用于计算两个字符串之间的相似度,而且还提供排序接口能从大量候选集中找到最相似的句子. (1)安装 pip install fuzzywuzzy (2)接口说明 两个模块:fuzz, process,fuzz主要用于两字符串之间匹配,process主要用于搜索排序. fuzz.ratio(s1,s2)直接计算s1和s2之间的相似度,返回值为0-100,100表示完全相同: fuzz.partial_rat

  • Python实现字符串模糊匹配方式

    目录 Python字符串模糊匹配 包含四个参数 python-re模块,模糊匹配 Python字符串模糊匹配 Python的difflib库中get_close_matches方法 包含四个参数 x:被匹配的字符串. words:去匹配的字符串列表. n,前topn个最佳匹配返回,默认为3. cutoff:匹配度大小,为[0, 1]浮点数,默认数值0.6. import difflib list1 = ['ape', 'apple', 'peach', 'puppy'] difflib.get_

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

    需求: 准入授权配置文件有时候分了好几个维度进行配置,例如 company|product|sys这种格式的配置: 1.配置 "sina|weibo|pusher" 表示 sina公司weibo产品pusher系统能够准入,而"sina|weibo|sign"不允许准入 2.配置 "sina|*|pusher" 表示sina公司所有产品的pusher系统都能够准入 3.配置 "*|*|pusher" 表示所有公司的所有产品的p

  • 正则表达式实现字符的模糊匹配功能示例

    本文实例讲述了正则表达式实现字符的模糊匹配功能.分享给大家供大家参考,具体如下: package com.cn.util; import java.util.regex.Pattern; /** * 正则表达式 工具类 * * @author lifangyu */ public class RegexUtil { /* * IP地址的匹配标达式 ( // \\d{1,3}) // :\d // 0~9数字,{1,3} // 至少一位,最多三位) */ private static String

  • IOS实现邮箱模糊匹配的功能

    先来看看要实现的效果图 一.介绍一下功能 当输入一个邮箱的数字,会默认在后面匹配出来@qq.com,当然这个默认@qq.com可以换成其他的如@163.com等等.这里默认是@qq.com,因为我们的产品汪做过统计大多数用户还是用的qq邮箱,所以默认是@qq.com. 当输入@符号还是不会有所变化,但是如果在@之后再输入字符,会将这个字符和你想要提示的邮箱后缀做匹配,我这里是需要匹配@qq.com,@163.com,@126.com,@yahoo.com,@139.com,@henu.com类型

  • Java实现的模糊匹配某文件夹下的文件并删除功能示例

    本文实例讲述了Java实现的模糊匹配某文件夹下的文件并删除功能.分享给大家供大家参考,具体如下: package com.wyebd.gis; import java.io.File; /** * @Title: DelFiles.java * @Package com.wyebd.gis * @Description: * @author lisr * @date Mar 7, 2012 5:36:03 PM * @version V1.0 */ public class DelFiles {

  • Java替换中使用正则表达式实现中间模糊匹配的方法

    使用".+?"实现中间模糊匹配的代码: public class Test { public static void main(String[] args) { String str="总会在某一个回眸的时刻醉了流年,濡湿了柔软的心.总会有某一个回眸的时刻醉了流年,濡湿了柔软的心"; str=str.replaceAll("总会在.+?流年", "总会有某一个回眸的时刻醉了流年"); System.out.println(st

  • python 已知一个字符,在一个list中找出近似值或相似值实现模糊匹配

    已知一个元素,在一个list中找出相似的元素 使用场景: 已知一个其它来源的字符串, 它有可能是不完全与我数据库中相应的字符串匹配的,因此,我需要将其转为适合我数据库中的字符串 使用场景太绕了, 直接举例来说吧 随便举例: 按青岛城市的城区来说, 我数据库中存储的城区是个list:['市北区', '市南区', '莱州市', '四方区']等 从其它的数据来源得到一个城区是:市北 我怎么得到与市北相似相近的市北区 解决方案: In [1]: import difflib In [2]: cityar

  • shell模糊匹配与正则详解

    前言: 正则可以实现一些简单的功能,并用在脚本中,如检测ip地址是否符合规范,检测文件名是否符合规范等等. 正则表达式 正则表达式主要是用来描述一个句法规则的模式.其实说的通俗一点,就是利用字符和元字符的组合,对一些符合既定句法的模式进行模糊匹配.它的主要功能是文本查询和字符串操作. 正则表达式的基本元素包括普通字符和元字符,在Linux shell里面,常用的正则表达式元字符集为:S={*  .  ^  $  []  \  \<\>  \{\}  \{n,\}  \{n,m\} },每一个元

随机推荐