php trim源码分析
本文同时发表于https://github.com/zhangyachen/zhangyachen.github.io/issues/9
核心代码如下:
/* {{{ php_trim()
* mode 1 : trim left
* mode 2 : trim right
* mode 3 : trim left and right
* what indicates which chars are to be trimmed. NULL->default (' \t\n\r\v\0')
*/
PHPAPI char *php_trim(char *c, int len, char *what, int what_len, zval *return_value, int mode TSRMLS_DC)
{
register int i;
int trimmed = 0;
char mask[256];
if (what) {
php_charmask((unsigned char*)what, what_len, mask TSRMLS_CC);
} else {
php_charmask((unsigned char*)" \n\r\t\v\0", 6, mask TSRMLS_CC);
}
//从左开始
if (mode & 1) {
for (i = 0; i < len; i++) {
if (mask[(unsigned char)c[i]]) { //该位置有第二个参数对应的值
trimmed++;
} else {
break;
}
}
len -= trimmed;
c += trimmed;
}
if (mode & 2) {
for (i = len - 1; i >= 0; i--) {
if (mask[(unsigned char)c[i]]) {
len--;
} else {
break;
}
}
}
if (return_value) {
//把c指针现在指向的位置以后的len个字符返回
RETVAL_STRINGL(c, len, 1);
} else {
return estrndup(c, len);
}
return "";
}
可以看出,在php_trim函数内部调用了php_charmask函数
/* {{{ php_charmask
* Fills a 256-byte bytemask with input. You can specify a range like 'a..z',
* it needs to be incrementing.
* Returns: FAILURE/SUCCESS whether the input was correct (i.e. no range errors)
*/
static inline int php_charmask(unsigned char *input, int len, char *mask TSRMLS_DC)
{
unsigned char *end;
unsigned char c;
int result = SUCCESS;
memset(mask, 0, 256); //初始化一个长度为256的hash表
for (end = input+len; input < end; input++) {
c=*input;
if ((input+3 < end) && input[1] == '.' && input[2] == '.'
&& input[3] >= c) {
memset(mask+c, 1, input[3] - c + 1);
input+=3;
} else if ((input+1 < end) && input[0] == '.' && input[1] == '.') {
/* Error, try to be as helpful as possible:
(a range ending/starting with '.' won't be captured here) */
if (end-len >= input) { /* there was no 'left' char */
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, no character to the left of '..'");
result = FAILURE;
continue;
}
if (input+2 >= end) { /* there is no 'right' char */
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, no character to the right of '..'");
result = FAILURE;
continue;
}
if (input[-1] > input[2]) { /* wrong order */
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range, '..'-range needs to be incrementing");
result = FAILURE;
continue;
}
/* FIXME: better error (a..b..c is the only left possibility?) */
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid '..'-range");
result = FAILURE;
continue;
} else {
//对应的位置为1
mask[c]=1;
}
}
return result;
}
可以看出trim函数的逻辑:
1 声明一个长度为256的hash表。
2 将character_mask中每个字节转化为ascii码,将hash表中ascii码对应key的value设置为1。
3 从头部遍历str中每个字节,若遍历到字节对应的ascii码在hash表中存在,则str长度位置减1;若不存在,就中断循环。
4 从尾部遍历str中每个字节,逻辑同3。
案例分析:
trim("广东省","省")导致乱码
首先获得"广东省"的十六进制表示
<?php
// 文件utf-8编码
// 获取字符串编码
function get_hex_str($str) {
$hex_str = '';
for ($i = 0; $i < strlen($str); $i ++) {
$ord = ord($str[$i]);//转换为ascii码
$hex_str .= sprintf("\x%02X", $ord);//以十六进制输出,2为指定的输出字段的宽度.如果位数小于2,则左端补0
}
return $hex_str;
}
$str = "广东省";
printf("str[%s] hex_str[%s]\n", \(str, get_hex_str(\)str));
\(str = trim(\)str, "省");
printf("str[%s] hex_str[%s]\n", \(str, get_hex_str(\)str));
输出:
str[广东省] hex_str[\xE5\xB9\xBF\xE4\xB8\x9C\xE7\x9C\x81]
str[广hex_str[\xE5\xB9\xBF\xE4\xB8]
utf-8编码下汉字对应三个字节,“东”的编码为e4 b8 9c,“省”的编码为e7 9c 81。
trim("广东省", "省"); 函数处理时不是以我们看到的中文字符为一个单位,而是以字节为单位。
相等于从e5 b9 bf e4 b8 9c e7 9c 81开头和结尾去掉包含在e7 9c 81的字节,这样“东”的第三个字节就会被切掉,就会有上述的输出了。
如果想将中文字符串中部分字符去掉,建议使用str_replace。
php trim源码分析的更多相关文章
- jQuery-1.9.1源码分析系列(十四) 一些jQuery工具
为了给下一章分析动画处理做准备,先来看一下一些工具.其中队列工具在动画处理中被经常使用. jQuery.fn. queue(([ queueName ] [, newQueue ]) || ([ qu ...
- angular源码分析:angular中脏活累活承担者之$parse
我们在上一期中讲 $rootscope时,看到$rootscope是依赖$prase,其实不止是$rootscope,翻看angular的源码随便翻翻就可以发现很多地方是依赖于$parse的.而$pa ...
- [源码]String StringBuffer StringBudlider(2)StringBuffer StringBuilder源码分析
纵骑横飞 章仕烜 昨天比较忙 今天把StringBuffer StringBulider的源码分析 献上 在讲 StringBuffer StringBuilder 之前 ,我们先看一下 ...
- angular源码分析:angular中jqLite的实现——你可以丢掉jQuery了
一.从function JQLite(element)函数开始. function JQLite(element) { if (element instanceof JQLite) { //情况1 r ...
- jQuery原型属性constructor,selector,length,jquery和原型方法size,get,toArray源码分析
首先看一下在jQuery1.7.1中定义的原型属性和方法有哪些? init方法作为实际的构造函数已经详细分析过了,需要了解可以参考http://www.cnblogs.com/yy-hh/p/4492 ...
- JFinal 源码分析 [DB+ActiveRecord]
我记得以前有人跟我说,“面试的时候要看spring的源码,要看ioc.aop的源码"那为什么要看这些开源框架的源码呢,其实很多人都是"应急式"的去读,就像读一篇文章一下, ...
- Heritrix源码分析(九) Heritrix的二次抓取以及如何让Heritrix抓取你不想抓取的URL
本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.iteye.com/blog/644396 本博客已迁移到本人独立博客: http://www.yun5u ...
- Solr4.8.0源码分析(15) 之 SolrCloud索引深入(2)
Solr4.8.0源码分析(15) 之 SolrCloud索引深入(2) 上一节主要介绍了SolrCloud分布式索引的整体流程图以及索引链的实现,那么本节开始将分别介绍三个索引过程即LogUpdat ...
- Solr4.8.0源码分析(7)之Solr SPI
Solr4.8.0源码分析(7)之Solr SPI 查看Solr源码时候会发现,每一个package都会由对应的resources. 如下图所示: 一时对这玩意好奇了,看了文档以后才发现,这个serv ...
随机推荐
- 操作系统学习笔记----进程/线程模型----Coursera课程笔记
操作系统学习笔记----进程/线程模型----Coursera课程笔记 进程/线程模型 0. 概述 0.1 进程模型 多道程序设计 进程的概念.进程控制块 进程状态及转换.进程队列 进程控制----进 ...
- c语言捕捉异常
闲暇之日阅读lua源码,发现原来C语言除goto之外的另一个处理异常的方法.既为setjump longjump两个函数,setjump相当于try,longjump相当于catch.与goto不同的 ...
- 翻译连载 | 附录 A:Transducing(下)-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇
原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...
- 数细胞-swust oj
数细胞(0964) 一矩形阵列由数字0到9组成,数字1到9代表细胞,细胞的定义为沿细胞数字上下左右还是细胞数字则为同一细胞,求给定矩形阵列的细胞个数.编程需要用到的队列及其相关函数已经实现,你只需要完 ...
- 随笔-SQL的三种存储引擎即三种类型的表
MYSQL 的环境变量:......server/bin下 引擎(Engine):是电子平台上开发程序或系统的核心组件.利用引擎,开发者可迅速建立.铺设程序所需的功能,或利用其辅助程序的运转.一般而言 ...
- Jfinal启动原理及源码简析
以下所有源码只截取了部分代码,标题即为类名 1.Web.xml <filter-name>jfinal</filter-name> <filter-class>co ...
- C#爬虫系列(一)——国家标准全文公开系统
网上有很多Python爬虫的帖子,不排除很多培训班借着AI的概念教Python,然后爬网页自然是其中的一个大章节,毕竟做算法分析没有大量的数据怎么成. C#相比Python可能笨重了些,但实现简单爬虫 ...
- PAT 1002. A+B for Polynomials (25) 简单模拟
1002. A+B for Polynomials (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue T ...
- page 简单易懂 分页
基础分页功能 <?php class Page{ //$count是用户设定的值 public $a; function pages($count,$page_num,$url ...
- javascript设计模式——发布订阅模式
前面的话 发布—订阅模式又叫观察者模式,它定义对象间的一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知.在javascript开发中,一般用事件模型来替代传统的发布—订阅模 ...