[PHP源码阅读]strpos、strstr和stripos、stristr函数,strposstristr
strpos
<span>mixed</span> <span>strpos</span> ( <span>string</span> <span>$haystack</span>, <span>mixed</span> <span>$needle</span> [, int <span>$offset</span> = 0 ] )
如果offset指定了,查找会从offset的位置开始。offset不能为负数。
返回needle第一次出现在haystack的位置。如果在haystack中找不到needle,则返回FALSE。
needle,如果needle不是字符串,它会被转换成整型数值并赋值为该数值的ASCII字符。请看下面例子。
例子
<span>$str</span> = "hello"<span>; </span><span>$pos</span> = <span>strpos</span>(<span>$str</span>, 111<span>); </span><span>//</span><span> 111的ASCII值是o,因此$pos = 4</span>
strpos核心源码
<span>if</span> (Z_TYPE_P(needle) ==<span> IS_STRING) { </span><span>if</span> (!<span>Z_STRLEN_P(needle)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, </span><span>"</span><span>Empty needle</span><span>"</span><span>); RETURN_FALSE; } </span><span>//</span><span> 调用php_memnstr函数查找needle</span> found = php_memnstr(haystack +<span> offset, Z_STRVAL_P(needle), Z_STRLEN_P(needle), haystack </span>+<span> haystack_len); } </span><span>else</span><span> { </span><span>//</span><span> 如果不是字符串,转换成数字并赋值为该数字的ASCII字符。</span> <span>if</span> (php_needle_char(needle, needle_char TSRMLS_CC) !=<span> SUCCESS) { RETURN_FALSE; } </span><span>//</span><span>设置结束字符</span> needle_char[<span>1</span>] = <span>0</span><span>; found </span>= php_memnstr(haystack +<span> offset, needle_char, </span><span>1</span><span>, haystack </span>+<span> haystack_len);<br /> } }</span>
有一点要注意的是,如果needle不是字符串的话,会调用php_needle_char函数将needle转成整型数字并转换为其ASCII值。
查找函数
函数最后返回的是found,php_memnstr函数实现了查找的方法。那么再继续看看php_memnstr函数做了什么:
<span>#define</span> php_memnstr zend_memnstr
php_memnstr是函数zend_memnstr的宏定义,查看zend_memnstr函数如下:
<span>static</span> inline <span>char</span> *<span> zend_memnstr(</span><span>char</span> *haystack, <span>char</span> *needle, <span>int</span> needle_len, <span>char</span> *<span>end) { </span><span>char</span> *p =<span> haystack; </span><span>char</span> ne = needle[needle_len-<span>1</span><span>]; </span><span>if</span> (needle_len == <span>1</span><span>) { </span><span>return</span> (<span>char</span> *)memchr(p, *needle, (end-<span>p)); } </span><span>if</span> (needle_len > end-<span>haystack) { </span><span>return</span><span> NULL; } </span><span>//</span><span> 第一个优化,只查找end - needle_len次</span> end -=<span> needle_len; </span><span>while</span> (p <=<span> end) { </span><span>//</span><span> 第二个优化,先判断字符串的开头和结尾是否一样再判断整个字符串</span> <span>if</span> ((p = (<span>char</span> *)memchr(p, *needle, (end-p+<span>1</span>))) && ne == p[needle_len-<span>1</span><span>]) { </span><span>if</span> (!memcmp(needle, p, needle_len-<span>1</span><span>)) { </span><span>return</span><span> p; } } </span><span>if</span> (p ==<span> NULL) { </span><span>return</span><span> NULL; } p</span>++<span>; } </span><span>return</span><span> NULL; }</span>
第一个优化,因为(char *)memchr(p, *needle, (end-p+1)是在end - needle_len + 1(即haystack_len+1)中查找,如果p为空,说明needle的第一个字符在p中从未出现过。
strstr
<span>string</span> <span>strstr</span> ( <span>string</span> <span>$haystack</span>, <span>mixed</span> <span>$needle</span> [, bool <span>$before_needle</span> = <span>false</span> ] )
返回needle在haystack中第一次出现的位置到结束的字符串。
这个函数的区分大小写的。
如果needle在haystack中不存在,返回FALSE。
如果before_needle为true,则返回haystack中needle在haystack第一次出现的位置之前的字符串。
strstr核心源码
<span>if</span><span> (found) { </span><span>//</span><span> 计算出found的位置</span> found_offset = found -<span> haystack; </span><span>if</span><span> (part) { RETURN_STRINGL(haystack, found_offset, </span><span>1</span><span>); } </span><span>else</span><span> { RETURN_STRINGL(found, haystack_len </span>- found_offset, <span>1</span><span>); } }</span>
strstr函数的前半部分跟strpos类似,区别在于strstr函数在找到位置后,需要返回haystack部分的字符串。part变量就是调用strstr函数时传递的before_needle变量。
stripos
<span>mixed</span> <span>stripos</span> ( <span>string</span> <span>$haystack</span>, <span>string</span> <span>$needle</span> [, int <span>$offset</span> = 0 ] )
不区分大小写的strpos。实现方式跟下面的类似,主要是使用一份拷贝然后将需要比较的字符串转换成小写字符后进行再进行查找。
stristr
<span>string</span> <span>stristr</span> ( <span>string</span> <span>$haystack</span>, <span>mixed</span> <span>$needle</span> [, bool <span>$before_needle</span> = <span>false</span> ] )
不区分大小写的strstr。
核心源码
<span>//</span><span> 拷贝一份haystack</span> haystack_dup =<span> estrndup(haystack, haystack_len); </span><span>if</span> (Z_TYPE_P(needle) ==<span> IS_STRING) { </span><span>char</span> *<span>orig_needle; </span><span>if</span> (!<span>Z_STRLEN_P(needle)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, </span><span>"</span><span>Empty needle</span><span>"</span><span>); efree(haystack_dup); RETURN_FALSE; } orig_needle </span>=<span> estrndup(Z_STRVAL_P(needle), Z_STRLEN_P(needle)); </span><span>//</span><span> 调用php_stristr函数找出orig_needle的值。</span> found =<span> php_stristr(haystack_dup, orig_needle, haystack_len, Z_STRLEN_P(needle)); efree(orig_needle); } </span><span>else</span><span> { </span><span>if</span> (php_needle_char(needle, needle_char TSRMLS_CC) !=<span> SUCCESS) { efree(haystack_dup); RETURN_FALSE; } needle_char[</span><span>1</span>] = <span>0</span><span>; found </span>= php_stristr(haystack_dup, needle_char, haystack_len, <span>1</span><span>); } </span><span>if</span><span> (found) { found_offset </span>= found -<span> haystack_dup; </span><span>if</span><span> (part) { RETVAL_STRINGL(haystack, found_offset, </span><span>1</span><span>); } </span><span>else</span><span> { RETVAL_STRINGL(haystack </span>+ found_offset, haystack_len - found_offset, <span>1</span><span>); } } </span><span>else</span><span> { RETVAL_FALSE; } </span><span>//</span><span> 释放变量</span> efree(haystack_dup);
可以知道,found是从php_stristr中得到的,继续查看php_stristr函数:
PHPAPI <span>char</span> *php_stristr(<span>char</span> *s, <span>char</span> *<span>t, size_t s_len, size_t t_len) { php_strtolower(s, s_len); php_strtolower(t, t_len); </span><span>return</span> php_memnstr(s, t, t_len, s +<span> s_len); }</span>
这个函数的功能就是将字符串都转成小写之后调用php_mennstr函数来查找needle在haystack第一次出现的位置。
总结
因为strpos/stripos返回的是位置,位置从0开始计算,所以判断查找失败都用 === FALSE 更适合。
阅读PHP的源码收获挺多,一方面可以知道某个函数的具体实现原理是怎样的,另一方面可以学习到一些编程优化方案。
到此本文结束,如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。
如果本文对你有帮助,望点下推荐,谢谢^_^

php将16进制字符串转为数字的方法:1、使用hexdec()函数,语法“hexdec(十六进制字符串)”;2、使用base_convert()函数,语法“bindec(十六进制字符串, 16, 10)”。

PHP 是一门功能强大的编程语言,广泛应用于 Web 开发领域。其中一个非常常见的情况是需要将字符串转换为小数。这在进行数据处理的时候非常有用。在本文中,我们将介绍如何在 PHP 中将字符串转换为小数。

检测变量是否为字符串的方法:1、利用“%T”格式化标识,语法“fmt.Printf("variable count=%v is of type %T \n", count, count)”;2、利用reflect.TypeOf(),语法“reflect.TypeOf(变量)”;3、利用reflect.ValueOf().Kind()检测;4、使用类型断言,可以对类型进行分组。

php字符串长度不一致的解决办法:1、通过mb_detect_encoding()函数查看字符串的编码方式;2、通过mb_strlen函数查看具体字符长度;3、使用正则表达式“preg_match_all('/[\x{4e00}-\x{9fff}]+/u', $str1, $matches);”剔除非中文字符即可。

删除方法:1、使用TrimSpace()函数去除字符串左右两边的空格,语法“strings.TrimSpace(str)”;2、使用Trim()函数去除字符串左右两边的空格,语法“strings.Trim(str, " ")”;3、使用Replace()函数去除字符串的全部空格,语法“strings.Replace(str, " ", "", -1)”。

在开发PHP应用程序时,有时我们需要去掉字符串前面的某些特定字符或者字符串。在这种情况下,我们需要使用一些PHP函数来实现这一目标。本文将介绍一些PHP函数,帮助您轻松地去掉字符串前面的字符或字符串。

转换方法:1、在转换变量前加上用括号括起来的目标类型“(bool)”或“(boolean)”;2、用boolval()函数,语法“boolval(字符串)”;3、用settype()函数,语法“settype(变量,"boolean")”。

php字符串部分乱码的解决办法:1、使用“mb_substr(strip_tags($str),0,-1,'UTF-8');”截取字符串;2、使用“iconv("UTF-8","GB2312//IGNORE",$data)”转换字符集即可。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具

Dreamweaver Mac版
視覺化網頁開發工具

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。