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 相关文章推荐
第八节 访问方式 [8]
Oct 09 PHP
从C/C++迁移到PHP——判断字符类型的函数
Oct 09 PHP
用PHP实现ODBC数据分页显示一例
Oct 09 PHP
深入理解PHP中的Session和Cookie
Jun 21 PHP
Yii结合CKEditor实现图片上传功能
Jun 13 PHP
PHP使用ODBC连接数据库的方法
Jul 18 PHP
PHP内存使用情况如何获取
Oct 10 PHP
PHP中的静态变量及static静态变量使用详解
Nov 05 PHP
Yii2框架使用计划任务的方法
May 25 PHP
PHP上传Excel文件导入数据到MySQL数据库示例
Oct 25 PHP
PHP工厂模式简单实现方法示例
May 23 PHP
php+Ajax无刷新验证用户名操作实例详解
Mar 04 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
E路文章系统PHP
2006/12/11 PHP
利用curl 多线程 模拟 并发的详解
2013/06/14 PHP
CI框架AR数据库操作常用函数总结
2016/11/21 PHP
javascript背投广告代码的完善
2008/04/08 Javascript
jquery的Tooltip插件 qtip使用详细说明
2010/09/08 Javascript
js 跳出页面的frameset框架示例介绍
2013/12/23 Javascript
JS 操作Array数组的方法及属性实例解析
2014/01/08 Javascript
jquery实现保存已选用户
2014/07/21 Javascript
JQuery的Ajax中Post方法传递中文出现乱码的解决方法
2014/10/21 Javascript
jQuery的ready方法详解
2014/11/27 Javascript
使用nodejs下载风景壁纸
2017/02/05 NodeJs
浅谈angularjs依赖服务注入写法的注意点
2017/04/24 Javascript
iview同时验证多个表单问题总结
2018/09/29 Javascript
微信小程序自定义toast的实现代码
2018/11/16 Javascript
JS数组方法reverse()用法实例分析
2020/01/18 Javascript
python高并发异步服务器核心库forkcore使用方法
2013/11/26 Python
Python爬取读者并制作成PDF
2015/03/10 Python
python简单实例训练(21~30)
2017/11/15 Python
Pycharm设置界面全黑的方法
2018/05/23 Python
Tensorflow 训练自己的数据集将数据直接导入到内存
2018/06/19 Python
python+unittest+requests实现接口自动化的方法
2018/11/29 Python
Python面向对象之类和对象实例详解
2018/12/10 Python
python实现剪切功能
2019/01/23 Python
Python下应用opencv 实现人脸检测功能
2019/10/24 Python
Python qrcode 生成一个二维码的实例详解
2020/02/12 Python
利用Python自动化操作AutoCAD的实现
2020/04/01 Python
鲜果饮品店创业计划书
2014/01/21 职场文书
学生会招新策划书
2014/02/14 职场文书
省级优秀班集体申报材料
2014/05/25 职场文书
机关保密承诺书
2014/06/03 职场文书
党的群众路线教育实践活动组织生活会发言材料
2014/10/17 职场文书
同学毕业留言寄语
2015/02/27 职场文书
初中毕业生自我评价
2015/03/02 职场文书
酒店优秀员工推荐信
2015/03/24 职场文书
离婚上诉状范文
2015/05/23 职场文书
2016年度创先争优活动总结
2016/04/05 职场文书