深入理解PHP之strpos
概述
在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 <= end) {
// 第二个优化,先判断字符串的开头和结尾是否一样再判断整个字符串
if ((p = (const 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;
} 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 < 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的更多相关文章
- [译] 理解PHP内部函数的定义(给PHP开发者的PHP源码-第二部分)
文章来自:http://www.hoohack.me/2016/02/10/understanding-phps-internal-function-definitions-ch 原文:https:/ ...
- PHP代码审计04之strpos函数使用不当
前言 根据红日安全写的文章,学习PHP代码审计的第四节内容,题目均来自PHP SECURITY CALENDAR 2017,讲完题目会用一个实例来加深巩固,这是之前写的,有兴趣可以去看看: PHP代码 ...
- 理解CSS视觉格式化
前面的话 CSS视觉格式化这个词可能比较陌生,但说起盒模型可能就恍然大悟了.实际上,盒模型只是CSS视觉格式化的一部分.视觉格式化分为块级和行内两种处理方式.理解视觉格式化,可以确定得到的效果是应 ...
- 彻底理解AC多模式匹配算法
(本文尤其适合遍览网上的讲解而仍百思不得姐的同学) 一.原理 AC自动机首先将模式组记录为Trie字典树的形式,以节点表示不同状态,边上标以字母表中的字符,表示状态的转移.根节点状态记为0状态,表示起 ...
- 理解加密算法(三)——创建CA机构,签发证书并开始TLS通信
接理解加密算法(一)--加密算法分类.理解加密算法(二)--TLS/SSL 1 不安全的TCP通信 普通的TCP通信数据是明文传输的,所以存在数据泄露和被篡改的风险,我们可以写一段测试代码试验一下. ...
- node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理
一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...
- 如何一步一步用DDD设计一个电商网站(一)—— 先理解核心概念
一.前言 DDD(领域驱动设计)的一些介绍网上资料很多,这里就不继续描述了.自己使用领域驱动设计摸滚打爬也有2年多的时间,出于对知识的总结和分享,也是对自我理解的一个公开检验,介于博客园这个平 ...
- 学习AOP之透过Spring的Ioc理解Advisor
花了几天时间来学习Spring,突然明白一个问题,就是看书不能让人理解Spring,一方面要结合使用场景,另一方面要阅读源代码,这种方式理解起来事半功倍.那看书有什么用呢?主要还是扩展视野,毕竟书是别 ...
- ThreadLocal简单理解
在java开源项目的代码中看到一个类里ThreadLocal的属性: private static ThreadLocal<Boolean> clientMode = new Thread ...
随机推荐
- 【HDU 1588】 Gauss Fibonacci
[题目链接] 点击打开链接 [算法] 要求 f(g(0)) + f(g(1)) + f(g(2)) + ... + f(g(n-1)) 因为g(i) = k * i + b 所以原式 = f(b) + ...
- RDA Kconfig介绍 ***
安装显示库: sudo apt-get install libncurses5-dev libncursesw5-dev 执行相关文件: 1.radisson.Kconfig 2.gen_radiss ...
- uva10655
Given the value of a+b and ab you will have to find the value of a n + b n Input The input file cont ...
- 如何给自己的博客上添加个flash宠物插件
最近在一些博主的博客上看到一些小宠物的挂件,很有趣,访客到了网站后可以耍耍小宠物,增加网站的趣味性,在功能强大的博客系统上看到有这样的小宠物挂件还是蛮有趣的. 多次差找资料后,终于在http://ww ...
- 使用inet_ntoa() 时编译提示错误:
char*inet_ntoa(struct in_addr in)将一个IP转换成一个互联网标准点分格式的字符串. 我把 inet_ntoa 需要的头文件加上去: #include <sy ...
- javascript检测基本类型值或引用类型值的类型方法
首先javascript的数据类型分为两种数据类型:基本数据数据类型和引用数据类型 基本数据类型:Number,String,Boolean,Undefined,Null.原始值,是简单的数据段,可按 ...
- vue中sync,v-model----双向数据绑定
需求:父子组件同步数据 实现方式:sync或者v-model 一.sync 官网:https://cn.vuejs.org/v2/guide/components-custom-events.html ...
- 汇编程序52:实验15 安装新的int9中断例程
assume cs:code ;重写int9中断例程,当按住a后松开,便会产生满屏A stack segment dw dup() stack ends code segment start: mov ...
- 贪心 Codeforces Round #263 (Div. 2) C. Appleman and Toastman
题目传送门 /* 贪心:每次把一个丢掉,选择最小的.累加求和,重复n-1次 */ /************************************************ Author :R ...
- Android 性能优化(6)网络优化( 2) Analyzing Network Traffic Data:分析网络数据
Analyzing Network Traffic Data 1.This lesson teaches you to Analyze App Network Traffic Analyze Netw ...