深入理解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 ...
随机推荐
- bzoj2957 楼房重建——线段树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2957 线段树维护两个值:cnt 能看到的最多楼房数: mx 最大斜率数: 对于一段区间,从左 ...
- 私有CA和证书
证书类型 证书授权机构的证书 服务器 用户证书 获取证书两种方法 使用证书授权机构: 生成签名请求(csr ) 将csr发送给CA 从CA处接收签名 自签名的证书: 自已签发自己的公钥 openSSL ...
- hdu1213 并查集不压缩
题意:题意:一个人请人吃饭,相互认识的朋友在一张桌子,相互认识的朋友的意思是如果A认识B,B认识C,那么A.B.C是朋友,对于每组输入输出桌子的张数. Sample Input 2 5 3 1 2 2 ...
- bzoj 4300: 绝世好题【dp】
设f[i][j]表示数列到i为止最后一项第j位为1的最大子序列长度,每次从i-1中1<<j&a[i]!=0的位+1转移来 然后i维是不需要的,答案直接在dp过程中去max即可 #i ...
- bzoj 1914: [Usaco2010 OPen]Triangle Counting 数三角形【叉积+极角排序+瞎搞】
参考:https://blog.csdn.net/u012288458/article/details/50830498 有点神啊 正难则反,考虑计算不符合要求的三角形.具体方法是枚举每个点,把这个点 ...
- AtCoder Regular Contest 099 C~E
C - Minimization 枚举就可以了 因为最后一定会变成1,所以第一次操作的区间就包含1会比较优,然后枚举1在第一次操作区间里排第几个取min即可 #include<iostream& ...
- java Class.getResource和ClassLoader.getResource
http://www.cnblogs.com/wang-meng/p/5574071.html http://blog.csdn.net/earbao/article/details/50009241 ...
- Android 性能优化(22)*性能工具之「Hierarchy Viewer」 Hierarchy Viewer Walkthrough
Hierarchy Viewer Walkthrough 1.In this document Prerequisites Setting the ANDROID_HVPROTO variable W ...
- ASP.NET GridView 控件绑定 CheckBoxList
需求:设计这样一个页面,在页面上可以自由选择和展示各省份下城市? 思路:一次性查询出所需的记录(查询数据库的操作不宜写到 C# 代码的循环语句中),并保存到全局变量中,之后根据条件过滤出需要的.可以在 ...
- Spring框架学习-Spring和IOC概述
一:什么是Spring框架? spring是一个分层的javase/EEfull-stack(一站式)轻量级的java开源框架.是为了解决企业开发的复杂性而创建的.框架的主要优势是分层架构,Sprin ...