PHP中strpos、strstr和stripos、stristr函数分析


Posted in PHP onJune 11, 2016

本文为大家分析了 PHP中strpos、strstr和stripos、stristr函数,供大家参考,具体内容如下

strpos

mixed strpos ( string $haystack, mixed $needle [, int $offset = 0 ] )
如果offset指定了,查找会从offset的位置开始。offset不能为负数。

返回needle第一次出现在haystack的位置。如果在haystack中找不到needle,则返回FALSE。

needle,如果needle不是字符串,它会被转换成整型数值并赋值为该数值的ASCII字符。请看下面例子。

例子

$str = "hello";
$pos = strpos($str, 111);
// 111的ASCII值是o,因此$pos = 4
strpos核心源码

if (Z_TYPE_P(needle) == IS_STRING) {
   if (!Z_STRLEN_P(needle)) {
     php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty needle");
     RETURN_FALSE;
   }

   // 调用php_memnstr函数查找needle
   found = php_memnstr(haystack + offset,
              Z_STRVAL_P(needle),
              Z_STRLEN_P(needle),
              haystack + haystack_len);
   } else {
     // 如果不是字符串,转换成数字并赋值为该数字的ASCII字符。
     if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) {
        RETURN_FALSE;
     }
     //设置结束字符
     needle_char[1] = 0;
     found = php_memnstr(haystack + offset,
              needle_char,
              1,
              haystack + haystack_len);
 }
}

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

查找函数

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

#define php_memnstr zend_memnstr
php_memnstr是函数zend_memnstr的宏定义,查看zend_memnstr函数如下:

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 == 1) {
    return (char *)memchr(p, *needle, (end-p));
  }

  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;
}

第一个优化,因为(char *)memchr(p, *needle, (end-p+1)是在end ? needle_len + 1(即haystack_len+1)中查找,如果p为空,说明needle的第一个字符在p中从未出现过。

strstr

string strstr ( string $haystack, mixed $needle [, bool $before_needle = false ] )

返回needle在haystack中第一次出现的位置到结束的字符串。
这个函数的区分大小写的。

如果needle在haystack中不存在,返回FALSE。

如果before_needle为true,则返回haystack中needle在haystack第一次出现的位置之前的字符串。

strstr核心源码

if (found) {
    // 计算出found的位置
    found_offset = found - haystack;
    if (part) {
      RETURN_STRINGL(haystack, found_offset, 1);
    } else {
      RETURN_STRINGL(found, haystack_len - found_offset, 1);
    }
}

strstr函数的前半部分跟strpos类似,区别在于strstr函数在找到位置后,需要返回haystack部分的字符串。part变量就是调用strstr函数时传递的before_needle变量。

stripos

mixed stripos ( string $haystack, string $needle [, int $offset = 0 ] )

不区分大小写的strpos。实现方式跟下面的类似,主要是使用一份拷贝然后将需要比较的字符串转换成小写字符后进行再进行查找。

stristr

string stristr ( string $haystack, mixed $needle [, bool $before_needle = false ] ) 不区分大小写的strstr。

核心源码

// 拷贝一份haystack
haystack_dup = estrndup(haystack, haystack_len);

if (Z_TYPE_P(needle) == IS_STRING) {
  char *orig_needle;
  if (!Z_STRLEN_P(needle)) {
    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty needle");
    efree(haystack_dup);
    RETURN_FALSE;
  }
  orig_needle = estrndup(Z_STRVAL_P(needle), Z_STRLEN_P(needle));
  // 调用php_stristr函数找出orig_needle的值。
  found = php_stristr(haystack_dup, orig_needle,  haystack_len, Z_STRLEN_P(needle));
  efree(orig_needle);
} else {
  if (php_needle_char(needle, needle_char TSRMLS_CC) != SUCCESS) {
    efree(haystack_dup);
    RETURN_FALSE;
  }
  needle_char[1] = 0;

  found = php_stristr(haystack_dup, needle_char,  haystack_len, 1);
}

if (found) {
  found_offset = found - haystack_dup;
  if (part) {
    RETVAL_STRINGL(haystack, found_offset, 1);
  } else {
    RETVAL_STRINGL(haystack + found_offset, haystack_len - found_offset, 1);
  }
} else {
  RETVAL_FALSE;
}

// 释放变量
efree(haystack_dup);

可以知道,found是从php_stristr中得到的,继续查看php_stristr函数:

PHPAPI char *php_stristr(char *s, char *t, size_t s_len, size_t t_len)
{
  php_strtolower(s, s_len);
  php_strtolower(t, t_len);
  return php_memnstr(s, t, t_len, s + s_len);
}

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

总结

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

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

以上就是本文的全部内容,希望对大家学习php程序设计有所帮助。

PHP 相关文章推荐
php&amp;java(一)
Oct 09 PHP
php输入流php://input使用示例(php发送图片流到服务器)
Dec 25 PHP
PHP中使用json数据格式定义字面量对象的方法
Aug 20 PHP
php带抄送和密件抄送的邮件发送方法
Mar 20 PHP
作为程序员必知的16个最佳PHP库
Dec 09 PHP
实现PHP框架系列文章(6)mysql数据库方法
Mar 04 PHP
centos 7.2下搭建LNMP环境教程
Nov 20 PHP
利用PHPExcel实现Excel文件的写入和读取
Apr 26 PHP
Yii框架参数化查询中IN查询只能查询一个的解决方法
May 20 PHP
PHP开发之用微信远程遥控服务器
Jan 25 PHP
php中上传文件的的解决方案
Sep 25 PHP
Laravel 数据库加密及数据库表前缀配置方法
Oct 10 PHP
linux下php上传文件注意事项
Jun 11 #PHP
php设计模式之单例模式代码
Jun 11 #PHP
浅谈PHP Cookie处理函数
Jun 10 #PHP
php单例模式的简单实现方法
Jun 10 #PHP
PHP操作mysql数据库分表的方法
Jun 09 #PHP
浅谈PHP链表数据结构(单链表)
Jun 08 #PHP
PHP Yaf框架的简单安装使用教程(推荐)
Jun 08 #PHP
You might like
上海无线电三厂简史修改版
2021/03/01 无线电
PHP 闭包详解及实例代码
2016/09/28 PHP
php json_encode与json_decode详解及实例
2016/12/13 PHP
PHP正则匹配到2个字符串之间的内容方法
2018/12/24 PHP
js 对象是否存在判断
2009/07/15 Javascript
讨论javascript(一)工厂方式 js面象对象的定义方法
2009/12/15 Javascript
原生js实现shift/ctrl/alt按键的获取
2013/04/08 Javascript
jquery实现的下拉和收缩效果示例
2014/08/21 Javascript
jQuery简单实现QQ空间点赞已经取消点赞
2015/04/02 Javascript
jQuery短信验证倒计时功能实现方法详解
2016/05/25 Javascript
indexedDB bootstrap angularjs之 MVC DOMO (应用示例)
2016/06/20 Javascript
js前端日历控件(悬浮、拖拽、自由变形)
2017/03/02 Javascript
详解vue-router 初始化时做了什么
2018/06/11 Javascript
vue中设置height:100%无效的问题及解决方法
2018/07/27 Javascript
JS中自定义事件的使用与触发操作实例分析
2019/11/01 Javascript
react使用CSS实现react动画功能示例
2020/05/18 Javascript
Openlayers绘制地图标注
2020/09/28 Javascript
python实现读取命令行参数的方法
2015/05/22 Python
详解python如何调用C/C++底层库与互相传值
2016/08/10 Python
Python实现的三层BP神经网络算法示例
2018/02/07 Python
python深度优先搜索和广度优先搜索
2018/02/07 Python
实例详解Python装饰器与闭包
2019/07/29 Python
Python脚本去除文件的只读性操作
2020/03/05 Python
Django与pyecharts结合的实例代码
2020/05/13 Python
python搜索算法原理及实例讲解
2020/11/18 Python
如何用python爬取微博热搜数据并保存
2021/02/20 Python
CSS中的字体大小设置属性总结
2016/05/24 HTML / CSS
Boden美国官网:英伦原创时装品牌
2017/07/03 全球购物
法国春天百货官网:Printemps.com
2020/06/29 全球购物
自考生自我鉴定范文
2013/10/01 职场文书
领导班子遵守党的政治纪律情况对照检查材料
2014/09/26 职场文书
2015年全国科普日活动总结
2015/03/23 职场文书
大学生先进个人主要事迹材料
2015/11/04 职场文书
CocosCreator入门教程之网络通信
2021/04/16 Javascript
Java常用工具类汇总 附示例代码
2021/06/26 Java/Android
使用SQL实现车流量的计算的示例代码
2022/02/28 SQL Server