深入理解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 ...
随机推荐
- 【USACO 2008FEB】 旅馆
[题目链接] 点击打开链接 [算法] 线段树 对于一个节点,记录它从左端点延伸的最多的空房间的个数,从右端点延伸的最多的空房间个数,和该区间最多的连续 空房间个数 [代码] #include<b ...
- bzoj1604
treap+并查集 我们能想到一个点和最近点对连接,用并查集维护,但是这个不仅不能求,而且还是不对的,于是就看了题解 把距离转为A(x-y,x+y),这样两点之间的距离就是max(x'-X',y'-Y ...
- [入门帮助] Kafka入门经典教程
问题导读 1.Kafka独特设计在什么地方?2.Kafka如何搭建及创建topic.发送消息.消费消息?3.如何书写Kafka程序?4.数据传输的事务定义有哪三种?5.Kafka判断一个节点是否活着有 ...
- hdu1213 并查集不压缩
题意:题意:一个人请人吃饭,相互认识的朋友在一张桌子,相互认识的朋友的意思是如果A认识B,B认识C,那么A.B.C是朋友,对于每组输入输出桌子的张数. Sample Input 2 5 3 1 2 2 ...
- noip2016 小结(ac两题+学习总结)
NOIP2016考试小结 DAY 1 T1 题目描述 小南有一套可爱的玩具小人, 它们各有不同的职业. 有一天, 这些玩具小人把小南的眼镜藏了起来. 小南发现玩具小人们围成了一个圈,它们有的面朝圈内, ...
- 一些常见的iOS面试问题,一眼就能看出 初级和高级工程师的区别
前言 面试题中有一些一般性的问题,通常是会问到的.面试iOS应聘者时,切入点很重要,不同的切入点会导致不同的结果,没有找到合适的切入点也无法对应聘者有一个全面的了解. 所以下面的面试问题更多的是提供方 ...
- [Qt Creator 快速入门] 第1章 Qt Creator简介
Qt Creator 是一个跨平台的.完整的 Qt 集成开发环境,其中包括了高级C++代码编辑器.项目和生成管理工具.集成的上下文相关的帮助系统.图形化调试器.代码管理和浏览工具等.这一章先对 Qt ...
- fprintf写入字符串入文件/fread读取文件内的字符串
#include <stdio.h> #include <string.h> #include <stdlib.h> int main(void) { FILE * ...
- selenium + python实现截图并且保存图片
webdriver的截图功能十分强悍,无论页面多长,webdriver都能比较完美的截到完整的页面. python代码: # -*- coding: utf-8 -*-from selenium im ...
- 【转】Spark:Master High Availability(HA)高可用配置的2种实现
原博文出自于: 感谢! Spark Standalone集群是Master-Slaves架构的集群模式,和大部分的Master-Slaves结构集群一样,存在着Master单点故障的问题.如何解决这个 ...