今天和同事在讨论关键字过虑的算法实现,前几天刚看过布隆过滤算法,于是就想起我们公司内部的查找关键字程序,好奇是怎么实现的。于是查找了一下源代码,原来可以简单地用stripos函数查找,
stripos原型如下:
int stripos ( string $haystack, string $needle [, int $offset] )
一般地都会建一个关键词库,然后把 用户输入的内容作为haystack,然后循环遍历一下关键词库,把每个关键词作为needle,如果存在的话则会返回关键字在输入的内容中的位置。
于是查找了一下PHP源代码关于这个函数的实现,如果想知道一个函数在PHP的哪个模块的话可以简单写一个函数get_module. php

<?php

if(substr(php_sapi_name(),0,6)=='cli'){
&nbsp;&nbsp;&nbsp;&nbsp;//命令行模式

&nbsp;&nbsp;&nbsp;&nbsp;global $argv;
&nbsp;&nbsp;&nbsp;&nbsp;$function = $argv[1];
}else{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//网页方式

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$function = $_GET['name'];
}
$extensions = get_loaded_extensions();
foreach($extensions as $t){
&nbsp;&nbsp;&nbsp;&nbsp;$modules_funcs = get_extension_funcs($t);
&nbsp;&nbsp;&nbsp;&nbsp;if(in_array($function, (array)$modules_funcs)){
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$is_found = true;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo "$function is in $t module\n";
&nbsp;&nbsp;&nbsp;&nbsp;}
}
if(!$is_found)echo "$function not found";

?>

字符串系列的函数属于PHP的标准模块,在ext/standard目录下,string.c 文件。

PHP_FUNCTION(stripos)
{
    char *found = NULL;
    char *haystack;
    int haystack_len;
    long offset = 0;
    char *needle_dup = NULL, *haystack_dup;
    char needle_char[2];
    zval *needle;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|l", &haystack, &haystack_len, &needle, &offset) == FAILURE) {
        return;
    }
        检查参数,第一第二个是必选参数,第三个是可选,|表示后面的参数都是可选的。

if (offset < 0 || offset > haystack_len) {
        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset not contained in string");
        RETURN_FALSE;
    }

if (haystack_len == 0) {
        RETURN_FALSE;
    }

haystack_dup = estrndup(haystack, haystack_len);
        //与大小写无关,所以先把字符全部转换成小写

php_strtolower(haystack_dup, haystack_len);

if (Z_TYPE_P(needle) == IS_STRING) {
               //第二个参数如果是字符串

if (Z_STRLEN_P(needle) == 0 || Z_STRLEN_P(needle) > haystack_len) {
            efree(haystack_dup);
            RETURN_FALSE;
        }

needle_dup = estrndup(Z_STRVAL_P(needle), Z_STRLEN_P(needle));
        php_strtolower(needle_dup, Z_STRLEN_P(needle));
                //这个是关键,由php_memnstr实现

found = php_memnstr(haystack_dup + offset, needle_dup, Z_STRLEN_P(needle), haystack_dup + haystack_len);
    } else {
               //第二个参数是数字的话,则强制转换成(char)类型

switch (Z_TYPE_P(needle)) {
            case IS_LONG:
            case IS_BOOL:
                needle_char[0] = tolower((char) Z_LVAL_P(needle));
                break;
            case IS_DOUBLE:
                needle_char[0] = tolower((char) Z_DVAL_P(needle));
                break;
            default:
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "needle is not a string or an integer");
                efree(haystack_dup);
                RETURN_FALSE;
                break;

}
        needle_char[1] = '\0';
        found = php_memnstr(haystack_dup + offset,
                            needle_char,
                            sizeof(needle_char) - 1,
                            haystack_dup + haystack_len);
    }

efree(haystack_dup);
    if (needle_dup) {
        efree(needle_dup);
    }

if (found) {
                //如何找到,则返回在这个字符串中的位置

RETURN_LONG(found - haystack_dup);
    } else {
        RETURN_FALSE;
    }
}

查找函数是由php_memstr实现的,在main目录下的php.h文件
#define php_memnstr zend_memnstr

所以真正的函数是zend_memnstr,在zend/目录下面的zend_operators.h,

static inline char *
zend_memnstr(char *haystack, char *needle, int needle_len, char *end)
{
    char *p = haystack;
    char ne = needle[needle_len-1];

end -= needle_len;

while (p <= end) {
        if ((p = (char *)memchr(p, *needle, (end-p+1))) && ne == p[needle_len-1]) {
            if (!memcmp(needle, p, needle_len-1)) {
                return p;
            }
        }

if (p == NULL) {
            return NULL;
        }

p++;
    }

return NULL;
}

查到这里就能看到实现搜索的原理了,主要用了一个while循环和两个C的函数memchr和memcmp。
先用第一个函数查找needle的第一个字符在haystack中出现的位置,然后调用memcmp,从这个位置开始比较needle和haystack,如果相同就返回这个位置,没有的话再把指针指向haystack的下一位再进行比较,一直到最后。
不过这个搜索只是简单地调用了memchr和memcmp函数,至于memcmp用了什么算法比较两个字符串就不太清楚,我们知道在一个长度为n的字符串里面查找字符串为m的字符串,那么最坏的 时间复杂度是O(n*m),上网搜了一下memcmp,不过没有找到他的实现原理。后来想了一下发现这个其实就是最简单的两次循环遍历进行比较。看了一下PHP的其他几个字符串查找函数strstr,stristr,strpos,strrpos,strripos 等函数都是调用zend_memnstr这个函数实现的,只是在返回的时候内容不同而已。

PHP源代码分析-字符串搜索系列函数实现详解相关推荐

  1. C语言中itoa系列函数及sprintf系列函数使用详解

    C语言中itoa系列函数及sprintf系列函数使用详解 itoa函数系列 该系列函数是广泛使用的非标准C语言和C++语言扩展功能,只能在windows编译器下使用,如果涉及到跨平台是不允许使用的,这 ...

  2. C语言中的字符串转数字函数常见问题详解

    目录 C语言中的字符串转数字函数常见问题详解 字符串转整形 atoi函数 字符串转长整形 strtol函数, C语言中的字符串转数字函数常见问题详解 字符串转整形 atoi函数 函数原型: int a ...

  3. MediaInfo源代码分析 4:Inform()函数

    ===================================================== MediaInfo源代码分析系列文章列表: MediaInfo源代码分析 1:整体结构 Me ...

  4. MediaInfo源代码分析 2:API函数

    ===================================================== MediaInfo源代码分析系列文章列表: MediaInfo源代码分析 1:整体结构 Me ...

  5. MediaInfo源代码分析 3:Open()函数

    ===================================================== MediaInfo源代码分析系列文章列表: MediaInfo源代码分析 1:整体结构 Me ...

  6. c语言fputc输入字符串,C语言fgetc和fputc函数用法详解(以字符形式读写文件)

    C语言fgetc和fputc函数用法详解(以字符形式读写文件),文件,字符,指针,函数,字节 C语言fgetc和fputc函数用法详解(以字符形式读写文件) 易采站长站,站长之家为您整理了C语言fge ...

  7. 【Python入门】Python字符串的45个方法详解

    Python中字符串对象提供了很多方法来操作字符串,功能相当丰富.必须进行全面的了解与学习,后面的代码处理才能更得心应手,编程水平走向新台阶的坚实基础.目前一共有45个方法,给大家分类整理,可以收藏查 ...

  8. PointNet系列代码复现详解(1)—PointNet分类部分

    想尽快入门点云,因此就从这个经典的点云处理神经网络开始.源码已经有了中文注释,但在一些对于自己不理解的地方添加了一些注释.欢迎大家一起讨论. 代码是来自github:GitHub - yanx27/P ...

  9. ioctl 函数 参数 详解

    2019独角兽企业重金招聘Python工程师标准>>> ioctl 函数 参数 详解 2009-04-24 11:55 ioctl函数 本函数影响由fd参数引用的一个打开的文件. # ...

最新文章

  1. Gitlab+Gerrit+Jenkins完整对接
  2. java 通配符 泛型_java中泛型之类型通配符(?)
  3. java做直播需要哪些技术_直播APP开发中需要解决哪些技术难点?千联信息
  4. 【笔记】Comparison of Object Detection and Patch-Based Classification Deep Learning Models on Mid- to La
  5. 华农c语言计算高精度加法_考研计算机 | 运算符与表达式算术运算符
  6. javascript闭包,你大爷永远是你大爷
  7. 使用Boxfuse轻松在云中运行Spring Boot应用程序
  8. 外设驱动库开发笔记4:AD9833函数发生器驱动
  9. 微信支付小年上线“点鞭炮,响优惠”活动 大额提现免费券限时发放
  10. 基于JAVA+SpringMVC+Mybatis+MYSQL的体育竞赛比赛赛事管理系统
  11. Netty in action—单元测试
  12. ABBYY FineReader PDF for Mac(PDF转换工具)
  13. HTML5应用——欢乐老虎机
  14. 从网络安装debian到使用中遇到的问题
  15. 2020中级计算机工程师,2020年上半年中级网络工程师报考详解
  16. c++ 解析纯真IP数据库qqwry
  17. 黑马12月开班时间出炉!戳文章免费试学!
  18. 苹果怎么设置铃声?设置自己喜欢的歌曲作为铃声,一招搞定!
  19. 【类不类三】来自星星的哥顿人与正则表达式
  20. 解决‘parent.relativePath‘ of POM xxx points at yyy instead of zzz please verify your project structure

热门文章

  1. php不可执行会怎样,从PHP运行可执行文件而不会产生shell
  2. oracle外部表使用详解,详解Oracle外部表的一次维护(图文)
  3. python生成试卷制卷系统_Python 读写文件 小应用:生成随机的测验试卷文件
  4. 【机器视觉案例】(5) AI视觉,远程手势控制虚拟计算器,附python完整代码
  5. 全国计算机建模三等奖,2009年全国数学建模真题(论文获国家 三等奖).doc
  6. java程序员可以只用windos吗_程序员要写多少代码 才能开发一个window操作系统
  7. python数据分析面试_python数据分析面试
  8. 二十岁出头的时候上,你一无所有,你拥有一切
  9. java c 解决方案_Java jdk安装及javac命令无效解决方案
  10. VSCode设置折叠左侧资源管理器所有文件夹的快捷键Alt+X、切换左侧活动栏显示隐藏快捷键Alt+Q