Table des matières
[PHP源码阅读]strpos、strstr和stripos、stristr函数,strposstristr
strpos
例子
strpos核心源码
查找函数
strstr
strstr核心源码
stripos
stristr
核心源码
总结
Maison développement back-end tutoriel php [PHP源码阅读]strpos、strstr和stripos、stristr函数,strposstristr_PHP教程

[PHP源码阅读]strpos、strstr和stripos、stristr函数,strposstristr_PHP教程

Jul 12, 2016 am 08:52 AM
字符串

[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 ] )
Copier après la connexion

如果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>
Copier après la connexion

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>
Copier après la connexion

有一点要注意的是,如果needle不是字符串的话,会调用php_needle_char函数将needle转成整型数字并转换为其ASCII值。

查找函数

函数最后返回的是found,php_memnstr函数实现了查找的方法。那么再继续看看php_memnstr函数做了什么:

<span>#define</span> php_memnstr zend_memnstr
Copier après la connexion

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>
Copier après la connexion

第一个优化,因为(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> ] )
Copier après la connexion

返回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>
Copier après la connexion

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 ] )
Copier après la connexion

不区分大小写的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> ] )
Copier après la connexion

不区分大小写的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);
Copier après la connexion

可以知道,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>
Copier après la connexion

这个函数的功能就是将字符串都转成小写之后调用php_mennstr函数来查找needle在haystack第一次出现的位置。

总结

因为strpos/stripos返回的是位置,位置从0开始计算,所以判断查找失败都用  === FALSE 更适合。

阅读PHP的源码收获挺多,一方面可以知道某个函数的具体实现原理是怎样的,另一方面可以学习到一些编程优化方案。

 

到此本文结束,如果还有什么疑问或者建议,可以多多交流,原创文章,文笔有限,才疏学浅,文中若有不正之处,万望告知。

如果本文对你有帮助,望点下推荐,谢谢^_^

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/1125523.htmlTechArticle[PHP源码阅读]strpos、strstr和stripos、stristr函数,strposstristr strpos mixed strpos ( string $haystack , mixed $needle [, int $offset = 0 ] ) 如果offset指定了,查找...
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn

Article chaud

Repo: Comment relancer ses coéquipiers
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Combien de temps faut-il pour battre Split Fiction?
3 Il y a quelques semaines By DDD
R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
1 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: Comment obtenir des graines géantes
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌

Article chaud

Repo: Comment relancer ses coéquipiers
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Combien de temps faut-il pour battre Split Fiction?
3 Il y a quelques semaines By DDD
R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
1 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: Comment obtenir des graines géantes
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌

Tags d'article chaud

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Explication détaillée de la méthode de conversion du type int en chaîne en PHP Explication détaillée de la méthode de conversion du type int en chaîne en PHP Mar 26, 2024 am 11:45 AM

Explication détaillée de la méthode de conversion du type int en chaîne en PHP

Comment déterminer si une chaîne Golang se termine par un caractère spécifié Comment déterminer si une chaîne Golang se termine par un caractère spécifié Mar 12, 2024 pm 04:48 PM

Comment déterminer si une chaîne Golang se termine par un caractère spécifié

Comment vérifier si une chaîne commence par un caractère spécifique en Golang ? Comment vérifier si une chaîne commence par un caractère spécifique en Golang ? Mar 12, 2024 pm 09:42 PM

Comment vérifier si une chaîne commence par un caractère spécifique en Golang ?

Comment répéter une chaîne dans le didacticiel de chaîne répétitive python_python Comment répéter une chaîne dans le didacticiel de chaîne répétitive python_python Apr 02, 2024 pm 03:58 PM

Comment répéter une chaîne dans le didacticiel de chaîne répétitive python_python

Comment résoudre le problème des caractères chinois tronqués lors de la conversion d'hexadécimaux en chaîne en PHP Comment résoudre le problème des caractères chinois tronqués lors de la conversion d'hexadécimaux en chaîne en PHP Mar 04, 2024 am 09:36 AM

Comment résoudre le problème des caractères chinois tronqués lors de la conversion d'hexadécimaux en chaîne en PHP

Manipulation de chaînes PHP : un moyen pratique de supprimer efficacement les espaces Manipulation de chaînes PHP : un moyen pratique de supprimer efficacement les espaces Mar 24, 2024 am 11:45 AM

Manipulation de chaînes PHP : un moyen pratique de supprimer efficacement les espaces

Conseils de correspondance de chaînes PHP : évitez les expressions incluses ambiguës Conseils de correspondance de chaînes PHP : évitez les expressions incluses ambiguës Feb 29, 2024 am 08:06 AM

Conseils de correspondance de chaînes PHP : évitez les expressions incluses ambiguës

Techniques PHP pour supprimer les deux derniers caractères d'une chaîne Techniques PHP pour supprimer les deux derniers caractères d'une chaîne Mar 23, 2024 pm 12:18 PM

Techniques PHP pour supprimer les deux derniers caractères d'une chaîne

See all articles