本文同时发表于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源码分析的更多相关文章

  1. jQuery-1.9.1源码分析系列(十四) 一些jQuery工具

    为了给下一章分析动画处理做准备,先来看一下一些工具.其中队列工具在动画处理中被经常使用. jQuery.fn. queue(([ queueName ] [, newQueue ]) || ([ qu ...

  2. angular源码分析:angular中脏活累活承担者之$parse

    我们在上一期中讲 $rootscope时,看到$rootscope是依赖$prase,其实不止是$rootscope,翻看angular的源码随便翻翻就可以发现很多地方是依赖于$parse的.而$pa ...

  3. [源码]String StringBuffer StringBudlider(2)StringBuffer StringBuilder源码分析

      纵骑横飞 章仕烜   昨天比较忙 今天把StringBuffer StringBulider的源码分析 献上   在讲 StringBuffer StringBuilder 之前 ,我们先看一下 ...

  4. angular源码分析:angular中jqLite的实现——你可以丢掉jQuery了

    一.从function JQLite(element)函数开始. function JQLite(element) { if (element instanceof JQLite) { //情况1 r ...

  5. jQuery原型属性constructor,selector,length,jquery和原型方法size,get,toArray源码分析

    首先看一下在jQuery1.7.1中定义的原型属性和方法有哪些? init方法作为实际的构造函数已经详细分析过了,需要了解可以参考http://www.cnblogs.com/yy-hh/p/4492 ...

  6. JFinal 源码分析 [DB+ActiveRecord]

    我记得以前有人跟我说,“面试的时候要看spring的源码,要看ioc.aop的源码"那为什么要看这些开源框架的源码呢,其实很多人都是"应急式"的去读,就像读一篇文章一下, ...

  7. Heritrix源码分析(九) Heritrix的二次抓取以及如何让Heritrix抓取你不想抓取的URL

    本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.iteye.com/blog/644396       本博客已迁移到本人独立博客: http://www.yun5u ...

  8. Solr4.8.0源码分析(15) 之 SolrCloud索引深入(2)

    Solr4.8.0源码分析(15) 之 SolrCloud索引深入(2) 上一节主要介绍了SolrCloud分布式索引的整体流程图以及索引链的实现,那么本节开始将分别介绍三个索引过程即LogUpdat ...

  9. Solr4.8.0源码分析(7)之Solr SPI

    Solr4.8.0源码分析(7)之Solr SPI 查看Solr源码时候会发现,每一个package都会由对应的resources. 如下图所示: 一时对这玩意好奇了,看了文档以后才发现,这个serv ...

随机推荐

  1. 利用docker搭建spark hadoop workbench

    目的 用docker实现所有服务 在spark-notebook中编写Scala代码,实时提交到spark集群中运行 在HDFS中存储数据文件,spark-notebook中直接读取 组件 Spark ...

  2. cardview和Palette,ActionBar颜色随图改变

    CardView是一个控件,Palette是取色工具(工具类),本文会对他们进行比较细致的介绍,相信机制的各位看完一定轻而易举地实现ActionBar随图改变的特效. 首先看一下效果图: Gradle ...

  3. iOS开发 关于addChildViewController的理解

    iOS开发 关于addChildViewController的理解 前言 我之前是做Android开发的接触ios开发不到一个月的时间,所以在有些东理解上会不自觉的向Android方向靠拢. 理解 通 ...

  4. kafka原理和实践(二)spring-kafka简单实践

    系列目录 kafka原理和实践(一)原理:10分钟入门 kafka原理和实践(二)spring-kafka简单实践 kafka原理和实践(三)spring-kafka生产者源码 kafka原理和实践( ...

  5. mysql插入测试数据

    使用php生成sql文件,然后再倒入mysql. 1.编写php代码 <?php set_time_limit(0); ini_set("memory_limit", &qu ...

  6. 浏览器输入URL加载的全过程都发生了什么事情,你知道?

    什么是URL: 统一资源定位符(URL,英文 Uniform / Universal Reaource Locator 的缩写) 标准的URL由服务类型(协议).存放资源的主机域名(可以是域名或者ip ...

  7. canvas入门之时钟的实现

    canvas 入门之作: 三步实现一个时钟: 直接上效果:   step 1  : 背景制作首先制作从1-12的数字: var canvas = document.getElementById('ca ...

  8. js屏蔽广告

    最近遇到有些广告的问题,首先是在手机端,可能是用户访问了一些小网站的,(你懂得),然后在访问我的网站时,会带小广告过来,通常是wifi被dns劫持的情况下导入到广告脚本, 1.处理这些要知道广告的根源 ...

  9. phpcms网站搬家 至 服务器 完整并且详细过程

    上传服务器空间后,才会通过搜索域名进行网页访问. 上传的过程肯定会有很多东西要修改,例如数据库怎么上传.路径怎么修改等..... 这就让大家看下,自己不断尝试后的完整搬家步骤!!! 一.上传服务器 ( ...

  10. gis电子地图开发公司面临的挑战和机遇

    从上个世纪90年代开始电子地图应用就已经收到人们的关注,但是由于时代的局限性和市场经济发展的不成熟.地理信息系统系统的应用并没有得到很好的利用.只有少数的国家机构和军事系统才能够使用这些应用.随着技术 ...