最近经常要对字符串进行匹配和替换操作,之前一般使用str_replace或者preg_replace,据说strtr的效率不错,所以对比了一下:
复制代码 代码如下:
$i = 0;
$t = microtime(true);
for(;$i{
$str = strtr(md5($i), $p2);
}
var_dump(microtime(true)-$t); //0.085476875305176
$t = microtime(true);
for(;$i{
$str = preg_replace($p, '', md5($i));
}
var_dump(microtime(true)-$t); //0.09863805770874
结果显示,strtr的效率比preg_replace高约15%左右。
趁着周末,查看了strtr的php源码:
复制代码 代码如下:
PHP_FUNCTION(strtr)
{
zval **str, **from, **to;
int ac = ZEND_NUM_ARGS();
//参数检查(zend_get_parameters_ex函数定义在zend_api.c文件中)
if (ac 3 || zend_get_parameters_ex(ac, &str, &from, &to) == FAILURE) {
WRONG_PARAM_COUNT;
}
//参数检查
if (ac == 2 && Z_TYPE_PP(from) != IS_ARRAY) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "The second argument is not an array.");
RETURN_FALSE;
}
convert_to_string_ex(str);
/* shortcut for empty string */
//宏Z_STRLEN_PP定义在zend_operators.h
if (Z_STRLEN_PP(str) == 0) {
RETURN_EMPTY_STRING();
}
if (ac == 2) {
php_strtr_array(return_value, Z_STRVAL_PP(str), Z_STRLEN_PP(str), HASH_OF(*from));
} else {
convert_to_string_ex(from);
convert_to_string_ex(to);
ZVAL_STRINGL(return_value, Z_STRVAL_PP(str), Z_STRLEN_PP(str), 1);
php_strtr(Z_STRVAL_P(return_value),
Z_STRLEN_P(return_value),
Z_STRVAL_PP(from),
Z_STRVAL_PP(to),
MIN(Z_STRLEN_PP(from),
Z_STRLEN_PP(to)));
}
}
先看看php_strtr函数:
复制代码 代码如下:
//trlen是字符串str_from与str_to的长度的最小值
PHPAPI char *php_strtr(char *str, int len, char *str_from, char *str_to, int trlen)
{
int i;
unsigned char xlat[256]; //
if ((trlen return str;
}
//xlat的下标与值相等
for (i = 0; i //把from到to字符串的每一个字符对应起来。例如:from="ab",to="cd",则会产生这样的对应'a'=>'c', 'b'=>'d'。
for (i = 0; i xlat[(unsigned char) str_from[i]] = str_to[i];
}
//替换(不过觉得这个函数的效率还有可以改进的地方,因为如果需要替换的字符只是占整个字符串很少的部分,这样就有大部分的赋值操作其实并没有什么意义,这样的情况下感觉先判断再赋值感觉会高效一点。有空测试一下)
for (i = 0; i str[i] = xlat[(unsigned char) str[i]];
}
return str;
}
可见,在处理strtr('abcdaaabcd', 'ab', 'efd')这样的操作时,应该是很高效的。
(注意:这个操作输出efcdeeefcd)
再看看php_strtr_array:
复制代码 代码如下:
static void php_strtr_array(zval *return_value, char *str, int slen, HashTable *hash)
{
zval **entry;
char *string_key;
uint string_key_len;
zval **trans;
zval ctmp;
ulong num_key;
int minlen = 128*1024;
int maxlen = 0, pos, len, found;
char *key;
HashPosition hpos;
smart_str result = {0};
HashTable tmp_hash;
//把替换数组从hash复制到tmp_hash,并记录下标字符串的最大和最小长度
zend_hash_init(&tmp_hash, 0, NULL, NULL, 0);
zend_hash_internal_pointer_reset_ex(hash, &hpos);
while (zend_hash_get_current_data_ex(hash, (void **)&entry, &hpos) == SUCCESS) {
switch (zend_hash_get_current_key_ex(hash, &string_key, &string_key_len, &num_key, 0, &hpos)) {
case HASH_KEY_IS_STRING:
len = string_key_len-1;
if (len zend_hash_destroy(&tmp_hash);
RETURN_FALSE;
}
zend_hash_add(&tmp_hash, string_key, string_key_len, entry, sizeof(zval*), NULL);
if (len > maxlen) {
maxlen = len;
}
if (len minlen = len;
}
break;
//下标如果是整形的话会转换成字符串类型,例如:array(10=>'aa')转换成array('10'=>'aa')
case HASH_KEY_IS_LONG:
Z_TYPE(ctmp) = IS_LONG;
Z_LVAL(ctmp) = num_key;
convert_to_string(&ctmp);
len = Z_STRLEN(ctmp);
zend_hash_add(&tmp_hash, Z_STRVAL(ctmp), len+1, entry, sizeof(zval*), NULL);
zval_dtor(&ctmp);
if (len > maxlen) {
maxlen = len;
}
if (len minlen = len;
}
break;
}
zend_hash_move_forward_ex(hash, &hpos);
}
key = emalloc(maxlen+1);
pos = 0;
//从字符串的第一个字符开始循环匹配,pos记录当前查找的位置
while (pos //当前位置加上最大长度,如果大于字符串长度,则最大长度就需要改变
if ((pos + maxlen) > slen) {
maxlen = slen - pos;
}
found = 0;
memcpy(key, str+pos, maxlen);
//从最大长度开始匹配,就是说对'abcd',若array('a'=>'e','ab'=>'f'),则会先把ab替换为f,而不是先把a换成e。
for (len = maxlen; len >= minlen; len--) {
key[len] = 0;
//因为使用了hash表,所以这样的效率还是挺高的
if (zend_hash_find(&tmp_hash, key, len+1, (void**)&trans) == SUCCESS) {
char *tval;
int tlen;
zval tmp;
if (Z_TYPE_PP(trans) != IS_STRING) {
tmp = **trans;
zval_copy_ctor(&tmp);
convert_to_string(&tmp);
tval = Z_STRVAL(tmp);
tlen = Z_STRLEN(tmp);
} else {
tval = Z_STRVAL_PP(trans);
tlen = Z_STRLEN_PP(trans);
}
//加入结果
smart_str_appendl(&result, tval, tlen);
//向前跳跃
pos += len;
found = 1;
if (Z_TYPE_PP(trans) != IS_STRING) {
zval_dtor(&tmp);
}
break;
}
}
if (! found) {
smart_str_appendc(&result, str[pos++]);
}
}
efree(key);
zend_hash_destroy(&tmp_hash);
smart_str_0(&result);
RETVAL_STRINGL(result.c, result.len, 0);
}
0
0
相关文章
CodeIgniter E-Library 教程:正确关联并展示多作者图书数据
怎么查看PHP信息_查看PHP配置详情的方式【操作】
PHP怎么发送电子邮件_PHP使用mail函数发送邮件教程【操作】
PHP连接数据库怎么实现_MySQL数据库操作详解【详解】
如何优雅替代 PHP 中的嵌套 foreach 循环实现多维数组扁平化
本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
热门AI工具
相关专题
本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。
797
2026.02.13
本专题系统整理微博网页版官方入口及网页端登录方式,涵盖首页直达地址、账号登录流程与常见访问问题说明,帮助用户快速找到微博官网主页,实现便捷、安全的网页端登录与内容浏览体验。
272
2026.02.13
本专题围绕Flutter框架展开,系统讲解跨平台UI构建原理与状态管理方案。内容涵盖Widget生命周期、路由管理、Provider与Bloc状态管理模式、网络请求封装及性能优化技巧。通过实战项目演示,帮助开发者构建流畅、可维护的跨平台移动应用。
144
2026.02.13
本专题面向前端开发者,深入讲解 TypeScript 类型系统与大型项目结构设计方法,并结合 Vite 构建工具优化前端工程化流程。内容包括模块化设计、类型声明管理、代码分割、热更新原理以及构建性能调优。通过完整项目示例,帮助开发者提升代码可维护性与开发效率。
25
2026.02.13
本专题围绕 Redis 在高并发系统中的应用展开,系统讲解主从复制、哨兵机制、Cluster 集群模式及数据分片原理。内容涵盖缓存穿透与雪崩解决方案、分布式锁实现、热点数据优化及持久化策略。通过真实业务场景演示,帮助开发者构建高可用、可扩展的分布式缓存系统。
92
2026.02.13
本专题系统整理雨课堂网页版官方入口及在线登录方式,涵盖账号登录流程、官方直连入口及平台访问方法说明,帮助师生用户快速进入雨课堂在线教学平台,实现便捷、高效的课程学习与教学管理体验。
15
2026.02.12
本专题汇总豆包AI官方网页版入口及在线使用方式,涵盖智能写作工具、图片生成体验入口和官网登录方法,帮助用户快速直达豆包AI平台,高效完成文本创作与AI生图任务,实现便捷智能创作体验。
717
2026.02.12
本专题面向后端开发与数据库工程师,深入讲解 PostgreSQL 查询优化原理与索引机制。内容包括执行计划分析、常见索引类型对比、慢查询优化策略、事务隔离级别以及高并发场景下的性能调优技巧。通过实战案例解析,帮助开发者提升数据库响应速度与系统稳定性。
64
2026.02.12
热门下载
相关下载
精品课程
最新文章


