PHP源码阅读笔记三:strrchr, strstr, stristr函数
string strrchr ( string haystack, string needle )
返回haystack中最后一个needle(字符)所在位置以后的字符串
如果needle为数字,将这个数字转化为这个值所对应的字符
如果needle多于一个字符串,则取第一个字符
如果haystack为一个数字,会将这个数字直接转化成字符串
程序中调用convert_to_string_ex(haystack);
在此函数的实现中,基本上是对一些特殊情况的处理(如上),
到最后就是定位最后一个needle出现的位置,返回根据位置返回此位置以后的字符串,如果此位置不存在,同返回false
string strstr ( string haystack, string needle )
此函数功能与strrchr类似,只不过它的needle允许为字符串,并且是查找needle第一个出现的位置,根据此位置返回之后的字符串,如果不存在则返回FALSE
在其代码中有一些特别的细节值得学习,如下所示代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | static inline char *zend_memnstr(char *haystack, char *needle, int needle_len, char *end) { char *p = haystack; char ne = needle[needle_len-1]; if(needle_len > end-haystack) { return NULL; } end -= needle_len; // 优化细节一,仅查找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; } |
以上代码是strstr和stristr函数实现的核心代码,功能:查找needle在haystack中首次出现的位置
string stristr ( string haystack, string needle )
stristr函数的功能与strstr类似,所不同的是其不区分大小写。
在PHP源码实现中主要区别是添加了将所有字符串转化为小写的操作,程序实现是在查找之前添加了如下代码:
1 2 3 | php_strtolower(s, s_len); php_strtolower(t, t_len); return php_memnstr(s, t, t_len, s + s_len); |
PS:在看源码的过程中,再次看了《再再认指针》的前面一段话,多了一些体会;
指针能够进行加减法,原因并不是因为它是指针,加减法则不是属于指针这种变量的,而是地址这种数据类型的本能,正是因为地址具有加减的能力,所以才使指针作为存放地址的变量能够进行加减运算。
这跟整数变量因为整数能够进行加减乘除因而它也能进行加减乘除一个道理。
查看《再再论指针》,请猛击再再论指针
奇怪为什么这段算法没有采用 KMP 呢?
个人觉得是效率与实现难度的平衡,可能与非ascii字符有关
#优化细节二,此处先判断字符串的开头和结尾的字符是否一样,如果一样则再判断整个字符串,提升性能
此处应该是先找到haystack 第一个匹配needle头字符的地址吧 再此基础上再匹配最后字符 再匹配所有字符