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生成静态页
Nov 25 PHP
解析php中的fopen()函数用打开文件模式说明
Jun 20 PHP
php增删改查示例自己写的demo
Sep 04 PHP
PHP 提取图片img标记中的任意属性的简单实例
Dec 10 PHP
PHP制作百度词典查词采集器
Jan 29 PHP
PHP实现搜索地理位置及计算两点地理位置间距离的实例
Jan 08 PHP
PHP使用PHPExcel删除Excel单元格指定列的方法
Jul 06 PHP
PHP多维数组排序array详解
Nov 21 PHP
实例解析php的数据类型
Oct 24 PHP
PHP实现单条sql执行多个数据的insert语句方法
Oct 11 PHP
解决thinkPHP 5 nginx 部署时,只跳转首页的问题
Oct 16 PHP
php微信小程序解包过程实例详解
Mar 31 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
php下载远程文件类(支持断点续传)
2008/11/14 PHP
Smarty中常用变量操作符汇总
2014/10/27 PHP
Laravel服务容器绑定的几种方法总结
2020/06/14 PHP
JavaScript Event学习第十章 一些可替换的事件对
2010/02/10 Javascript
13 个JavaScript 性能提升技巧分享
2012/07/26 Javascript
js拼接html注意问题示例探讨
2014/07/14 Javascript
JQuery中serialize()、serializeArray()和param()方法示例介绍
2014/07/31 Javascript
jQuery中index()的用法分析
2014/09/05 Javascript
JavaScript 学习笔记之数据类型
2015/01/14 Javascript
jQuery实现鼠标跟随提示层效果代码(可显示文本,Div,Table,Html等)
2016/04/18 Javascript
jquery获取复选框的值的简单实例
2016/05/26 Javascript
百度搜索框智能提示案例jsonp
2016/11/28 Javascript
使用Bootstrap美化按钮实例代码(demo)
2017/02/03 Javascript
使用重写url机制实现验证码换一张功能
2017/08/01 Javascript
Js利用console计算代码运行时间的方法示例
2017/09/24 Javascript
剖析Angular Component的源码示例
2018/03/23 Javascript
JavaScript实现邮箱后缀提示功能的示例代码
2018/12/13 Javascript
简介JavaScript错误处理机制
2020/08/04 Javascript
js+audio实现音乐播放器
2020/09/13 Javascript
vue vant中picker组件的使用
2020/11/03 Javascript
arcgis.js控制地图地体的显示范围超出区域自动弹回(实现思路)
2021/01/28 Javascript
进一步了解Python中的XML 工具
2015/04/13 Python
处理Python中的URLError异常的方法
2015/04/30 Python
python正则表达式的使用
2017/06/12 Python
python 类对象和实例对象动态添加方法(分享)
2017/12/31 Python
OpenCV-Python 摄像头实时检测人脸代码实例
2019/04/30 Python
python实现QQ邮箱发送邮件
2020/03/06 Python
Django Admin 上传文件到七牛云的示例代码
2020/06/20 Python
canvas如何绘制钟表的方法
2017/12/13 HTML / CSS
世界领先的在线地板和建筑材料批发商:BuildDirect
2017/02/26 全球购物
法国房车租赁网站:Yescapa
2019/08/26 全球购物
电子商务专业求职信
2014/03/08 职场文书
总经理秘书岗位职责
2014/03/17 职场文书
2014年人力资源工作总结
2014/11/19 职场文书
工程质量保证书
2015/05/09 职场文书
2015年食品安全宣传周活动总结
2015/07/09 职场文书