我的CSDN博客

strspn 这个库函数是真的很难理解,看了很多中文描述,反正都是不知所云,给出一系列的例子,结果也是让我瞠目结舌,荒唐、荒谬、荒诞!

特此记录理解过程,最后竟然是百度百科让我明白了这个库函数的意思。

中文的描述真的是太困难了,想用一两句话去说清楚往往不知所云。百度百科上最后给出了这个函数的定义,也就是这个函数是如何实现的,看了几遍才恍然大悟!

因此我也按照这个理解的顺序给出解释(没有耐心读的,不要往下看了,用心的东西往往需要花时间体会!),先给出函数的定义:

  1. int strspn(const char *s,const char *accept)
  2. {
  3. const char *p;
  4. const char *a;
  5. int count = 0;
  6. for(p = s; *p != '\0'; ++p)
  7. {
  8. for (a = accept; *a != '\0'; ++a)
  9. {
  10. if (*p == *a)
  11. {
  12. ++count;
  13. break;
  14. }
  15. } //里面的for循环到此为止
  16. if (*a == '\0')
  17. {
  18. return count;
  19. }
  20. } //外面的for循环到此为止
  21. return count;
  22. }

可以这么说,如果你看懂了这个函数定义,难道还不能理解这个函数?

比任何的中文解释更清晰!

那关键是你能看懂这个函数,如果看不懂那就回去再补补基础。

声明:下面这段中文解释如果看不懂,那就自己理解上面的程序,别看了,有些东西只可意会不可言传!

这里为了方便看,对上面函数的定义的要点提出来几点:

关键的是for循环语句的嵌套,内部for函数:

  1. for (a = accept; *a != '\0'; ++a)
  2. {
  3. if (*p == *a)
  4. {
  5. ++count;
  6. break;
  7. }
  8. } //里面的for循环到此为止

什么意思呢?就是将accept这个字符数组中的所有字符与目的字符数组 s 中的字符比较,如果相等,则计数器加1,那比较到什么时候结束呢?

比较到accept中的所有字符没有一个与s中字符相等,这时执行内层for循环后面的一条语句:

  1. if (*a == '\0')
  2. {
  3. return count;
  4. }

这不就是直接返回一个值,就是至此为止的计数值。


当你使用这个函数的使用,当然不需要自己定义,因为这是库函数中定义的,所以,你只需要源程序开头带上#include<string.h>这个头文件即可!

下面举几个例子,看看测试结果:

这是第一个测试的例子:

  1. #include <stdio.h>
  2. #include <string.h>
  3. int main () {
  4. int len;
  5. const char str1[] = "25,142,330,Smith,J,239-4123";
  6. const char str2[] = ",0123456789";
  7. len = strspn(str1, str2);
  8. printf("Length of initial segment matching %d\n", len );
  9. return(0);
  10. }

结果为:

在这个地方,发现了一个神器,在线写程序并编译的地址:Online C Compiler

http://tpcg.io/luVeGa

再给出一个测试例子:

  1. #include <stdio.h>
  2. #include <string.h>
  3. int main () {
  4. int len;
  5. const char str1[] = "25,142,330,Smith,J,239-4123";
  6. const char str2[] = "0123456789";
  7. len = strspn(str1, str2);
  8. printf("Length of initial segment matching %d\n", len );
  9. return(0);
  10. }


对了,还有一个于此互补的函数 strcspn,它的作用与上面的函数互补,为了说明清楚,我们给出两个函数的函数原型,便于讨论:

size_t strspn( char const *str, char const *group );

size_t strcspn( char const *str, char const *group );

group字符串指定一个或多个字符。strspn返回str起始部分匹配 group 中任意字符的字符数。这只是一个不太清晰的总结,具体看上面的内容。

strcspn函数和strspn函数正好相反,它对str字符串起始部分中不与group 中任何字符匹配的字符进行计数。 strcspn 这个名字中字母c来源于一组字符求补这个概念,也就是把这些字符换成原先并不存在的字符。

上面这一小段来自于《C与指针》,仅供参考,我也不太明白它在说什么?

举几个例子说明一下吧:

  1. #include <stdio.h>
  2. #include <string.h>
  3. int main () {
  4. int len;
  5. const char str1[] = ",142,330,Smith,J,239-4123";
  6. const char str2[] = "0123456789";
  7. len = strcspn(str1, str2);
  8. printf("Length of initial segment matching %d\n", len );
  9. return(0);
  10. }

str2字符数组中每一个字符都不与str1字符数组中的第一个字符相等,故计数加1,然后str2中有字符与str1第2个字符匹配的了,说了函数直接返回结果为1.

为了与之对比,我在举一个例子:

  1. #include <stdio.h>
  2. #include <string.h>
  3. int main () {
  4. int len;
  5. const char str1[] = ",,,Smith,J,239-4123";
  6. const char str2[] = "0123456789";
  7. len = strcspn(str1, str2);
  8. printf("Length of initial segment matching %d\n", len );
  9. return(0);
  10. }


这里根据我的想法,我想给出strcspn的大致定义,应该是这样的:


  1. int strcspn(const char *s,const char *accept)
  2. {
  3. const char *p;
  4. const char *a;
  5. int count = 0;
  6. for(p = s; *p != '\0'; ++p)
  7. {
  8. for (a = accept; *a != '\0'; ++a)
  9. {
  10. if (*p == *a)
  11. {
  12. return count;
  13. }
  14. } //里面的for循环到此为止
  15. if (*a == '\0')
  16. {
  17. ++ count;
  18. }
  19. } //外面的for循环到此为止
  20. return count;
  21. }

不信的话,下面我来测试下它的功能:

  1. #include <stdio.h>
  2. #include <string.h>
  3. int main () {
  4. int len;
  5. const char str1[] = ",,,Smith,J,239-4123";
  6. const char str2[] = "0123456789";
  7. //函数原型
  8. int my_strcspn(const char *s,const char *accept);
  9. len = my_strcspn(str1, str2);
  10. printf("Length of initial segment matching %d\n", len );
  11. return(0);
  12. }
  13. int my_strcspn(const char *s,const char *accept)
  14. {
  15. const char *p;
  16. const char *a;
  17. int count = 0;
  18. for(p = s; *p != '\0'; ++p)
  19. {
  20. for (a = accept; *a != '\0'; ++a)
  21. {
  22. if (*p == *a)
  23. {
  24. return count;
  25. }
  26. } //里面的for循环到此为止
  27. if (*a == '\0')
  28. {
  29. ++ count;
  30. }
  31. } //外面的for循环到此为止
  32. return count;
  33. }

运行得到:

运行示意

可见,结果符合预期!

就到这里吧,最后给出几个不错的网址:

https://baike.baidu.com/item/strspn

https://www.tutorialspoint.com/c_standard_library/c_function_strspn.htm

【 C 】高级字符串查找之 strspn 和 strcspn 的思考的更多相关文章

  1. 【 C 】高级字符串查找之查找标记(token)函数 strtok介绍

    我的csdn博客 一个字符串常常包含几个单独的部分,它们彼此被分隔开来.每次为了处理这些部分,你首先必须把它们从字符串中抽取出来. 这个任务有#include<string.h>中的str ...

  2. C/C++字符串查找函数

    C/C++ string库(string.h)提供了几个字符串查找函数,如下: memchr 在指定内存里定位给定字符 strchr 在指定字符串里定位给定字符 strcspn 返回在字符串str1里 ...

  3. C/C++字符串查找函数 <转>

    C/C++ string库(string.h)提供了几个字符串查找函数,如下: memchr 在指定内存里定位给定字符 strchr 在指定字符串里定位给定字符 strcspn 返回在字符串str1里 ...

  4. Rabin-Karp指纹字符串查找算法

    首先计算模式字符串的散列函数, 如果找到一个和模式字符串散列值相同的子字符串, 那么继续验证两者是否匹配. 这个过程等价于将模式保存在一个散列表中, 然后在文本中的所有子字符串查找. 但不需要为散列表 ...

  5. 自己动手写文件查找,字符串查找,查询jar包等工具

    文件查找——搜索当前目录下的文件 知道大概的文件名称,使用 findf FileName findf.py import argparse, re, os from os.path import jo ...

  6. 关于字符串查找 charindex ,Patindex 还有一个like

    字符串查找.在模糊朝找的情况下,其实3者的效率是差不多的.都需要一个一个取出来然后扫一遍╮(╯_╰)╭.然而用法还是会有一点儿的区别 1 charindex (查找的字符串,字符串表达式[,开始查找的 ...

  7. python 字符串查找

    python 字符串查找有4个方法,1 find,2 index方法,3 rfind方法,4 rindex方法. 1 find()方法: )##从下标1开始,查找在字符串里第一个出现的子串:返回结果3 ...

  8. Sunday算法(字符串查找、匹配)

    字符串查找算法中,最著名的两个是KMP算法(Knuth-Morris-Pratt)和BM算法(Boyer-Moore).两个算法在最坏情况下均具有线性的查找时间.但是在实用上,KMP算法并不比最简单的 ...

  9. lintcode:strStr 字符串查找

    题目: 字符串查找 字符串查找(又称查找子字符串),是字符串操作中一个很有用的函数.你的任务是实现这个函数. 对于一个给定的 source 字符串和一个 target 字符串,你应该在 source ...

随机推荐

  1. Python学习---JSON学习180130

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.JSON是用字符串来表示Javascript对象: Json字符串就是js对象的一种表现形式(字符串的形式 ...

  2. 将旧的时间字符串转换为新的string时间字符串

    旧的时间字符串-->simpledataformat1.parse(该字符串) 获得date类型 -->simpledataformat2.format(date) simpledatef ...

  3. MongoDB命令及其MongoTemplate的混合讲解

    前言 前面讲解了如何在springboot中集成mongodb,本文将讲解mongodb命令操作及其MongoTemplate的使用.穿插的目的在于不用先去寻找mongodb的命令又去寻找在java中 ...

  4. Web前端——jQuery----细节

    jQuery终极思想:创建jQuery对象(当发现相同的选择器在你的代码里出现多次时,请用变量把它储存起来.一切面向对象) 认识jQuery 1.jQuery库可以做什么? HTML元素选取 HTML ...

  5. css3 圣诞红包雨效果

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  6. JavaScript的事件对象中的特殊属性和方法(鼠标,键盘)

    鼠标操作导致的事件对象中的特殊属性和方法 鼠标事件是 Web 上面最常用的一类事件,毕竟鼠标还是最主要的定位设备.那么通过事件对象可以获取到鼠标按钮信息和屏幕坐标获取等 鼠标按钮 只有在主鼠标按钮被单 ...

  7. Django中模型(四)

    Django中模型(四) 五.创建对象 1.目的 向数据库中添加数据.当创建对象时,Django不会对数据库进行读写操作,当调用save()方法时,才与数据库交互,将对象保存到数据库中 2.注意 __ ...

  8. C++内存总结——开坑,随时总结添加

    C++内存区域分为:  程序代码区:存储程序代码的地方 栈区:编译器自动管理(分配释放)的内存区域,如函数参数,函数中的局部变量 堆区(又称动态存储区):由C语言中的函数malloc和free和C++ ...

  9. ubuntu使用----高效快捷键

    桌面快捷键 : ALT + F1: 聚焦到桌面左侧任务导航栏,可按上下键导航. ALT + F2: 运行命令 ALT + F4: 关闭窗口 ALT + TAB: 切换程序窗口 ALT + 空格: 打开 ...

  10. MySQL慢查询日志分析提取【转】

    原文:https://www.cnblogs.com/skymyyang/p/7239010.html 一:查询slow log的状态,如示例代码所示,则slow log已经开启. mysql> ...