概述

在php中经常用 strpos 判断字符串是否在另一个字符串中存在, 本文介绍 strpos 函数及其实现。

strpos应用

<?php
/* strpos示例 */ // test
echo 'match:', strpos('xasfsdfbk', 'xasfsdfbk') !== false ? 'true' : 'false', ';', PHP_EOL;
echo 'match:', strpos('xasfsdfbk', 'fbk') !== false ? 'true' : 'false', ';', PHP_EOL;
echo 'match:', strpos('xasfsdfbk', 'xs') != false ? 'true' : 'false', ';', PHP_EOL;
echo 'match:', strpos('xasfsdfbk', 'sfs') !== false ? 'true' : 'false', ';', PHP_EOL; // code
strpos('xasfsdfbk', 'sfs');

Warning: strpos 函数可能返回布尔值 FALSE,但也可能返回等同于 FALSE 的非布尔值。请阅读 布尔类型章节以获取更多信息。应使用 === 运算符来测试此函数的返回值。

strpos系列函数

函数 描述 版本
strpos 查找字符串首次出现的位置 PHP 4, PHP 5, PHP 7
stripos 查找字符串首次出现的位置(不区分大小写) PHP 5, PHP 7
strrpos 计算指定字符串在目标字符串中最后一次出现的位置 PHP 4, PHP 5, PHP 7
strripos 计算指定字符串在目标字符串中最后一次出现的位置(不区分大小写) PHP 5, PHP 7
mb_strpos 查找字符串在另一个字符串中首次出现的位置 PHP 4 >= 4.0.6, PHP 5, PHP 7
strstr 查找字符串的首次出现 PHP 4, PHP 5, PHP 7
stristr strstr() 函数的忽略大小写版本 PHP 4, PHP 5, PHP 7
substr_count 计算字串出现的次数 PHP 4, PHP 5, PHP 7

mb* 相关的函数也可, 比如说mb_strpos是基于字符数执行一个多字节安全的 strpos() 操作。

PHP(strpos)源码

strpos(ext/standard/string.c)

```
PHP_FUNCTION(strpos)
{
zval *needle;
zend_string *haystack;
char *found = NULL;
char needle_char[2];
zend_long offset = 0;

ifndef FAST_ZPP

if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|l", &haystack, &needle, &offset) == FAILURE) {
return;
}

else

ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(haystack)
Z_PARAM_ZVAL(needle)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(offset)
ZEND_PARSE_PARAMETERS_END();

endif

if (offset < 0) {
offset += (zend_long)ZSTR_LEN(haystack);
}
if (offset < 0 || (size_t)offset > ZSTR_LEN(haystack)) {
php_error_docref(NULL, E_WARNING, "Offset not contained in string");
RETURN_FALSE;
} if (Z_TYPE_P(needle) == IS_STRING) {
if (!Z_STRLEN_P(needle)) {
php_error_docref(NULL, E_WARNING, "Empty needle");
RETURN_FALSE;
} found = (char*)php_memnstr(ZSTR_VAL(haystack) + offset,
Z_STRVAL_P(needle),
Z_STRLEN_P(needle),
ZSTR_VAL(haystack) + ZSTR_LEN(haystack));
} else {
if (php_needle_char(needle, needle_char) != SUCCESS) {
RETURN_FALSE;
}
needle_char[1] = 0; found = (char*)php_memnstr(ZSTR_VAL(haystack) + offset,
needle_char,
1,
ZSTR_VAL(haystack) + ZSTR_LEN(haystack));
} if (found) {
RETURN_LONG(found - ZSTR_VAL(haystack));
} else {
RETURN_FALSE;
}

}


<h3>php_memnstr(main/php.h)</h3>
<ul><li><a href="https://github.com/php/php-src/blob/master/main/php.h" rel="nofollow noreferrer">PHP源码地址</a></li></ul>

define php_memnstr zend_memnstr /* 338 line*/


<h3>zend_memnstr(Zend/zend_operators.h)</h3>
<ul><li><a href="https://github.com/php/php-src/blob/master/Zend/zend_operators.h" rel="nofollow noreferrer">PHP源码地址</a></li></ul>

/*

  • 此函数的作用是在haystack中查找needle,如果不存在返回null,如果存在,返回指向haystack中needle头字符的指针

    */

    zend_memnstr(const char *haystack, const char *needle, size_t needle_len, const char *end)

    {

    const char *p = haystack;

    const char ne = needle[needle_len-1];

    ptrdiff_t off_p;

    size_t off_s;

    if (needle_len == 1) {

    return (const char *)memchr(p, *needle, (end-p));

    }

    off_p = end - haystack;

    off_s = (off_p > 0) ? (size_t)off_p : 0;

    if (needle_len > off_s) {

    return NULL;

    }

    if (EXPECTED(off_s < 1024 || needle_len < 3)) {

    // 第一个优化,只查找end - needle_len次

    end -= needle_len;

     while (p &lt;= end) {
    // 第二个优化,先判断字符串的开头和结尾是否一样再判断整个字符串
    if ((p = (const char *)memchr(p, *needle, (end-p+1))) &amp;&amp; ne == p[needle_len-1]) {
    if (!memcmp(needle, p, needle_len-1)) {
    return p;
    }
    } if (p == NULL) {
    return NULL;
    } p++;
    } return NULL;

    } else {

    return zend_memnstr_ex(haystack, needle, needle_len, end);

    }

    }


<h3>memchr(string.h)</h3>
<ul><li><a href="https://github.com/torvalds/linux/blob/master/lib/string.c" rel="nofollow noreferrer">Linux内核版-源码地址</a></li></ul>

/*

头文件:#include <string.h>

定义函数:void * memchr(const void *s, char c, size_t n);

函数说明:memchr()从头开始搜寻s 所指的内存内容前n 个字节,直到发现第一个值为c 的字节,则返回指向该字节的指针。

返回值:如果找到指定的字节则返回该字节的指针,否则返回0。

*/

ifndef __HAVE_ARCH_MEMCHR

void *memchr(const void *s, int c, size_t n)

{

const unsigned char *p = s;

while (n-- != 0) {

if ((unsigned char)c == *p++) {

return (void *)(p - 1);

}

}

return NULL;

}

EXPORT_SYMBOL(memchr);

endif


<h3>memcmp(string.h)</h3>
<ul><li><a href="https://github.com/torvalds/linux/blob/master/lib/string.c" rel="nofollow noreferrer">Linux内核版-源码地址</a></li></ul>

/* 字符串函数memcmp

原型:extern int memcmp(void *buf1, void *buf2, unsigned int count);

功能:比较内存区域buf1和buf2的前count个字节

说明:当buf1<buf2时,返回值<0  

  当buf1=buf2时,返回值=0   

当buf1>buf2时,返回值>0

*/

ifndef __HAVE_ARCH_MEMCMP

undef memcmp

__visible int memcmp(const void *cs, const void *ct, size_t count)

{

const unsigned char *su1, *su2;

int res = 0;

for (su1 = cs, su2 = ct; 0 &lt; count; ++su1, ++su2, count--)
if ((res = *su1 - *su2) != 0)
break;
return res;

}

EXPORT_SYMBOL(memcmp);

endif


<h2>提示</h2>
<p>strpos函数对大小写敏感。</p>
<h2>参考</h2>
<ul>
<li><a href="http://php.net/manual/zh/function.strpos.php" rel="nofollow noreferrer">php strpos官方文档</a></li>
<li><a href="https://segmentfault.com/a/1190000015776297">字符串查找算法</a></li>
</ul> 原文地址:https://segmentfault.com/a/1190000015786500

深入理解PHP之strpos的更多相关文章

  1. [译] 理解PHP内部函数的定义(给PHP开发者的PHP源码-第二部分)

    文章来自:http://www.hoohack.me/2016/02/10/understanding-phps-internal-function-definitions-ch 原文:https:/ ...

  2. PHP代码审计04之strpos函数使用不当

    前言 根据红日安全写的文章,学习PHP代码审计的第四节内容,题目均来自PHP SECURITY CALENDAR 2017,讲完题目会用一个实例来加深巩固,这是之前写的,有兴趣可以去看看: PHP代码 ...

  3. 理解CSS视觉格式化

    前面的话   CSS视觉格式化这个词可能比较陌生,但说起盒模型可能就恍然大悟了.实际上,盒模型只是CSS视觉格式化的一部分.视觉格式化分为块级和行内两种处理方式.理解视觉格式化,可以确定得到的效果是应 ...

  4. 彻底理解AC多模式匹配算法

    (本文尤其适合遍览网上的讲解而仍百思不得姐的同学) 一.原理 AC自动机首先将模式组记录为Trie字典树的形式,以节点表示不同状态,边上标以字母表中的字符,表示状态的转移.根节点状态记为0状态,表示起 ...

  5. 理解加密算法(三)——创建CA机构,签发证书并开始TLS通信

    接理解加密算法(一)--加密算法分类.理解加密算法(二)--TLS/SSL 1 不安全的TCP通信 普通的TCP通信数据是明文传输的,所以存在数据泄露和被篡改的风险,我们可以写一段测试代码试验一下. ...

  6. node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理

    一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...

  7. 如何一步一步用DDD设计一个电商网站(一)—— 先理解核心概念

    一.前言     DDD(领域驱动设计)的一些介绍网上资料很多,这里就不继续描述了.自己使用领域驱动设计摸滚打爬也有2年多的时间,出于对知识的总结和分享,也是对自我理解的一个公开检验,介于博客园这个平 ...

  8. 学习AOP之透过Spring的Ioc理解Advisor

    花了几天时间来学习Spring,突然明白一个问题,就是看书不能让人理解Spring,一方面要结合使用场景,另一方面要阅读源代码,这种方式理解起来事半功倍.那看书有什么用呢?主要还是扩展视野,毕竟书是别 ...

  9. ThreadLocal简单理解

    在java开源项目的代码中看到一个类里ThreadLocal的属性: private static ThreadLocal<Boolean> clientMode = new Thread ...

随机推荐

  1. Java 系统工具类 —— System、Scanner、Runtime

    0. 静态成员变量 System.out:是 PrinterStream 型变量: public final class System { ... public final static InputS ...

  2. bzoj 1924 所驼门王的宝藏

    题目大意: 有一个r*c的矩阵,上面有n个点有宝藏 每个有宝藏的点上都有传送门 传送门有三种:第一种可以传到该行任意一个有宝藏的点,第二种可以传到该列任意一个有宝藏的点,第三种可以传到周围的八连块上有 ...

  3. Linux-----Kconfig文件的简介

    内核源码树的目录下都有两个文件Kconfig和Makefile.分布到各目录的Kconfig构成了一个分布式的内核配置数据库, 每个Kconfig分别描述了所属目录源文件相关的内核配置菜单.在内核配置 ...

  4. Tool:Adobe Photoshop

    ylbtech-Tool-Adobe:Adobe Photoshop 1.返回顶部 1. Adobe Photoshop,简称“PS”,是由Adobe Systems开发和发行的图像处理软件. Pho ...

  5. 【高德地图API】绘制大地线 Geodesic/Great Circles

    大地线(geodesic)是指地球椭球面上连接两点的最短程曲线. 大地线上每点的密切面(无限接近的3个点所构成的平面)都包含此点的曲面法线.因曲面法线互不相交,故为一条空间曲面曲线.在球面上,大圆弧( ...

  6. 移动端html touch事件

    诸如智能手机和平板电脑一类的移动设备通常会有一(capacitive touch-sensitivescreen),以捕捉用户的手指所做的交互.随着移动网络的发展,其能够支持越来越复杂的应用,web开 ...

  7. PCB 机器学习(ML.NET)初体验实现PCB加投率预测

    使用ML.NET建立PCB加投率模型对单一蚀刻工序进行加投率预测, 此实例为最简单预测,要想实现全流程加投率预测挑战难度还是挺大的,可以查看另一种关于大数据在PCB行业应用---加投率计算基本原理:P ...

  8. 洛谷P1010 幂次方

    题目描述 任何一个正整数都可以用2的幂次方表示.例如 137=2^7+2^3+2^0 同时约定方次用括号来表示,即a^b 可表示为a(b). 由此可知,137137可表示为: 2(7)+2(3)+2( ...

  9. DFS POJ 1321 棋盘问题

    题目传送门 /* DFS:因为一行或一列都只放一个,可以枚举从哪一行开始放,DFS放棋子,同一列只能有一个 */ #include <cstdio> #include <algori ...

  10. 用Movie显示gif(2)GifView

    1,类 import android.annotation.SuppressLint; import android.content.Context; import android.content.r ...