C语言 字符串匹配

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言 字符串匹配相关的知识,希望对你有一定的参考价值。

给了一个二维char[4][12]数组,包含四个单词(关键字),每个单词短于12个字母,最后以\0结尾,每个单词占用一行。现在要求输入一个字符串,匹配是否是关键字,若是则输出,否则无视。特殊要求,除了自定义函数外,只能用getchar()和putchar()。
求……救……!

#include <stdio.h>
  
const char key[][12] =  "happy", "new", "year", "2014" ;
 
// 是否完全匹配某一个特定的 key 
int match1(const char *s, const char *t)

  while (*s && *t && *s++ == *t++);
  return !(*s || *t);

  
// 是否匹配一组 key 的中一个 
int match(const char *s)

  int i, j;
  for (i = 0; i < sizeof key / sizeof key[0]; i++)
    if (match1(s, key[i]))
    
      // 如果匹配到某个 key,则打印匹配到的 key 
      for (j = 0; key[i][j]; j++)  putchar(key[i][j]);
      putchar('\\n');
      return 1;
    
  return 0;

  
int main()

  char s[BUFSIZ];
  int i, k;
 
  // 输入一个字符串
  for (i = 0; i < BUFSIZ && (s[i] = getchar()) != '\\n'; i++);
  s[i] = '\\0';
  match(s);
  return 0;

以上程序是判断输入的字符串是否是某个 key 中的一个。



如果不要求完全匹配,而是要求检测输入的字符串是否含有某个 key,则程序如下:

#include <stdio.h>
  
const char key[][12] =  "happy", "new", "year", "2014" ;
 
// 是否含有某一个特定的 key 
int match1(const char *s, const char *t)

  const char *p, *q, *r;
  for (p = s, q = t; *p && *q; p = r, q = t)
  
    for (r = p + 1; *p == *q; p++, q++);
    if (*q == '\\0') return 1;
    if (*p == '\\0') return 0;
  
  return 0;

  
// 是否含有一组 key 的中一个 
int match(const char *s)

  int i, j;
  for (i = 0; i < sizeof key / sizeof key[0]; i++)
    if (match1(s, key[i]))
    
      // 如果匹配到某个 key,则打印匹配到的 key 
      for (j = 0; key[i][j]; j++)  putchar(key[i][j]);
      putchar('\\n');
      return 1;
    
  return 0;

  
int main()

  char s[BUFSIZ];
  int i, k;
 
  // 输入一个字符串
  for (i = 0; i < BUFSIZ && (s[i] = getchar()) != '\\n'; i++);
  s[i] = '\\0';
 
  if (match(s))
  
    // 如果匹配到某个 key,则打印输入的原始字符串 
    for (k = 0; k < i; k++) putchar(s[k]);
    putchar('\\n');
  
  return 0;

参考技术A
#define KEYNUM 4
#define KEYLEN 12
#define MAXCHAR 100

char a[MAXCHAR+1];

char * getline(int);
int cmp(char (*)[], char *);

int main()

char key[KEYNUM][KEYLEN]; //如关键字未指定,要求自己输入,则用这一行代码
//char key[KEYNUM][KEYLEN]="main","char","while","float"; //如关键字已指定,用这行并修改。 
char *p;
int i=0,j=0,ch;
//如关键字未指定,要求自己输入,则需要while这段代码 
/*--------------------------------*/
while(i<KEYNUM)

if((ch=getchar())!=EOF)

if(ch!='\\n'&&j<KEYLEN)
key[i][j++]=ch;
else

key[i][j]='\\0';
i++;
j=0;



///*如关键字已指定,中间这段代码变注释-------*/
p=getline(MAXCHAR);
if(cmp(key,p))
while(*p!='\\0')
putchar(*p++);
return 0;


char * getline(int num)
/*最多接收num个字符,返回字符串首地址,为了方便,把接收的字符数组变成全局变量*/

int i=0,ch;
while((ch=getchar())!=EOF&&ch!='\\n'&&i<num)
a[i++]=ch;
a[i]='\\0';
return a;


int cmp(char (*s)[KEYLEN], char *t)
/*用字符串t和关键字列表比较,如果匹配,返回所匹配的关键字列表序号,如不匹配,返回0 */

int i,flag=0;
char *p,*q;
for(i=0;i<KEYNUM;i++)

for(p=s[i],q=t;*q!='\\0'&&*p!='\\0';)

if(*p++==*q++)
flag=1;
else

flag=0;
break;


if(flag)
return i+1;

return 0;

参考技术B #include<stdio.h>
int main()

int i,j=0,k,n=0;
char a[4][12]="one","two","three","four";
char str[12];
for(i=0;i<12;i++)

str[i]=getchar(); //输入
n++; //计算长度
if(str[i]=='\\n')str[i]='\\0';break; //加上结束标志

for(i=0;i<4;i++)

if(a[i][0]==str[0]) //如果首字母匹配

while(str[j]==a[i][j])j++; //逐个匹配
if(j==n) //如果完全匹配

for(k=0;k<n;k++)putchar(str[k]); //输出
putchar('\\n');
break;
 


return 0;

算法"暴力"字符匹配算法的C语言实现



1、聊一聊

This browser does not support music or audio playback. Please play it in WeChat or another browser. 【算法】"暴力"字符匹配算法的C语言实现

    今天跟大家分享的这个曲子一般是在天气预报和英语试听中出现,不信你听一听绝对有种似曾相识感觉。

    本篇文章主要是为讲解高效字符匹配算法的一则预告文,跟大家讲讲暴力字符匹配算法以及匹配算法在通信中如何使用。

【算法】"暴力"字符匹配算法的C语言实现

2、暴力匹配算法介绍

1

聊聊字符匹配算法
    bug菌所说的暴力匹配算法就是C标准库函数strstr(),如果你还没有使用过或者没有听到过这个函数,那就有点......。
    字符匹配算法的应用其实是非常广泛的,小到信息的检索,大到网络安全监测,一种高效的字符匹配算法能够大大改善性能,所以目前对字符匹配算法的理论研究也是在一直进行着。

    可是理论算法研究和实际应用还是有一定的脱节,往往一些高级的算法并没有得到广泛的工程应用,面对目前快节奏的功能开发形成了 : "算法的思想越简单,实际应用的效果越好"的思想。

    所以bug菌从最简单的匹配算法跟大家讲起,对一些匹配性能要求不高的项目还是非常奏效的。


2

暴力字符匹配的实现原理

    暴力字符匹配算法的实现原理还是非常简单的,从第一个字符开始进行匹配,如果匹配不成功,移动到下一个字节重新开始逐个匹配,其实现过程如下图所示:

【算法】"暴力"字符匹配算法的C语言实现

    看似该算法实现得理所当然,不过对于部分情况其效率相对比较低下,看看如下情况:

【算法】"暴力"字符匹配算法的C语言实现

    上图是按照暴力字符匹配算法进行的匹配过程,我们如果仔细分析一下可以发现第二步的比较是必然不会成立的,因为第一步abab都匹配成功了,移动一位肯定是匹配不成功的,所以这样就增加了算法在时间上的复杂度,有没有更优的算法解决这个问题? 答案肯定是有的,下篇文章跟大家详细介绍。
   不过暴力匹配算法的好处就是理解上非常的简单,也可以说比较呆吧,往往简单的东西更加容易让大家接受,并且应用在实际的项目中,除非特别是对匹配效率比较敏感的项目。

3、暴力匹配的C代码实现

1

参考实现1

    strstr()既然是标准C库函数,那么稍微大一点的软件源码都会有相应的实现,一般都写得比较精炼的,那么看看Linux源码咯,于是截图了其实现函数供大家参考:


【算法】"暴力"字符匹配算法的C语言实现

【算法】"暴力"字符匹配算法的C语言实现

【算法】"暴力"字符匹配算法的C语言实现


    对于linux里面的strstr实现比较清晰,获得两个字符串的长度,然后逐位比较模式串与主串的长度,如果匹配返回成功,否则把主串指针移动一位继续循环比较。

    上面的代码看似比较简单,如果真的徒手写一个你还真不一定考虑得那么全面,比如下面几个细节:

  • memcmp采用const void *<参考:>,使得函数更加通用。

  • 内部for里面采用逗号表达式<参考:> ,程序更加紧凑、精炼。

  • 以及size_t是什么东西,为什么使用它?


2

参考实现2

    然而bug菌在翻阅一些代码中发现,还有strstr采用汇编来实现的,毕竟库函数相对比较固定,其主要是为了能够加快运算速度,下面是X86的strstr实现,供大家欣赏一下即可:

【算法】"暴力"字符匹配算法的C语言实现


3

简化版实现

    在平时的mcu开发中,bug菌不太喜欢调用库函数,就像上面的实现,一个不太复杂的程序里面进行了较多函数的嵌套,可能在性能强悍的芯片上倒问题不大,不过对于一些频繁使用该函数的中低端芯片来说性能上还是会有一定的损失的。

    所谓”高端秀功能,低端秀成本”,所以来个常用的简化版本,供大家参考:

 1#include <stdio.h>
2
3char* pChild = "123";
4char* pParent = "456789123789456123" ;
5
6char* strstr(const char*s1,const char*s2)
7{
8    int n;
9    if(*s2)
10    {
11        while(*s1)
12        {
13            for(n=0;*(s1+n)==*(s2+n);n++)
14            {
15                if(!*(s2+n+1))
16                    return(char*)s1;
17            }
18            s1++;
19        }
20        return NULL;
21    }
22    else
23        return (char*)s1;
24}
25
26int main(int argc, char *argv[]) {
27
28    printf("  %d\n",strstr(pParent,pChild) - pParent);
29    printf("公众号:最后一个bug\n");
30    return 0;
31}

4、暴力匹配在通信中的使用

1

应用
    如果仅仅只是匹配字符或者关键字等等,上面的代码 可以 直接拿来使用 ,在有些字节流的通信协议中都会存在帧头和帧尾的匹配问题,字符的匹配和帧头尾匹配思路上是一致的,所以仅仅只需要对函数进行改造以适应 字节数据查找 即可。

    一般都会把数据接收以后放入buff中,然后通过匹配算法查找帧头,帧尾,通过定位帧头进而确定通信格式数据完整性分析等。所以这里把字符匹配算法修改一下,获得如下代码:

 1typedef unsigned char uint8_t;
2typedef unsigned int  uint16_t;
3
4#include <stdio.h>
5
6uint8_t Head[3] = {0x01,0x02,0x03};
7uint8_t Buff[10] = {0x01,0x01,0x01,0x02,0x02,
8                    0x01,0x02,0x03,0x02,0x02};
9
10uint8_t* Bytestrstr(const uint8_t *s1 ,uint16_t len1,uint8_t*s2,uint16_t len2)
11{
12    uint16_t n;
13    uint16_t cnt;
14
15    if(*s2 || len2) 
16    {
17        for(cnt = 0;cnt < len1;cnt ++)
18        {
19            for(n=0;*(s1+n)==*(s2+n);n++)
20            {
21                if(n == (len2-1))
22                    return(uint8_t*)s1;
23            }
24            s1++;
25        }
26        return NULL;
27    }
28    else
29        return (char*)s1;
30}
31
32int main(int argc, char *argv[]) {
33
34    printf("  %d\n",Bytestrstr(Buff,10,Head,3) - Buff);
35    printf("公众号:最后一个bug\n");
36    return 0;
37}

    

    对于以后跟大家介绍的高效字符匹配算法经过类似修改以后均可以用到字节流传递过程中来。

5、最后小结

    暴力字符串匹配算法就说这么多了,下一篇跟大家聊聊KMP算法,同时说说上面文章<>,挺多小伙伴反馈说以为这篇文章是广告,如果是广告那肯定就不会让大家收藏了呀。【算法】"暴力"字符匹配算法的C语言实现

【算法】"暴力"字符匹配算法的C语言实现

推荐好文  点击蓝色字体即可跳转

【算法】"暴力"字符匹配算法的C语言实现

以上是关于C语言 字符串匹配的主要内容,如果未能解决你的问题,请参考以下文章

数据结构(C语言版)严蔚敏(字符串的模式匹配算法--KMP算法)

数据结构(C语言版)严蔚敏(字符串的模式匹配算法--KMP算法)

数据结构(C语言版)严蔚敏(字符串的模式匹配算法--KMP算法)

朴素模式匹配算法(C语言)

C语言的switch case 语句的case 常量 能匹配字符串常量吗?

字符串之KMP算法(C语言)