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开发中,一般用事件模型来替代传统的发布—订阅模 ...