官方手册中:

类似函数还有两个:ltrim() 和 rtrim()。分别处理字符串的左侧、右侧。

trim()的具体实现位于:ext/standard/string.c

/* {{{ proto string trim(string str [, string character_mask])
Strips whitespace from the beginning and end of a string */
PHP_FUNCTION(trim)
{
php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, );
}
/* }}} */
/* {{{ php_do_trim
* Base for trim(), rtrim() and ltrim() functions.
*/
static void php_do_trim(INTERNAL_FUNCTION_PARAMETERS, int mode)
{
zend_string *str;
zend_string *what = NULL; ZEND_PARSE_PARAMETERS_START(, )
Z_PARAM_STR(str)
Z_PARAM_OPTIONAL
Z_PARAM_STR(what)
ZEND_PARSE_PARAMETERS_END(); ZVAL_STR(return_value, php_trim(str, (what ? ZSTR_VAL(what) : NULL), (what ? ZSTR_LEN(what) : ), mode));
}
/* }}} */

具体实现:

 /* {{{ 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 zend_string *php_trim(zend_string *str, char *what, size_t what_len, int mode)
{
const char *c = ZSTR_VAL(str);
size_t len = ZSTR_LEN(str);
register size_t i;
size_t trimmed = ;
char mask[]; if (what) {
if (what_len == ) {
char p = *what;
if (mode & ) {
for (i = ; i < len; i++) {
if (c[i] == p) {
trimmed++;
} else {
break;
}
}
len -= trimmed;
c += trimmed;
}
if (mode & ) {
if (len > ) {
i = len - ;
do {
if (c[i] == p) {
len--;
} else {
break;
}
} while (i-- != );
}
}
} else {
php_charmask((unsigned char*)what, what_len, mask); if (mode & ) {
for (i = ; i < len; i++) {
if (mask[(unsigned char)c[i]]) {
trimmed++;
} else {
break;
}
}
len -= trimmed;
c += trimmed;
}
if (mode & ) {
if (len > ) {
i = len - ;
do {
if (mask[(unsigned char)c[i]]) {
len--;
} else {
break;
}
} while (i-- != );
}
}
}
} else {
if (mode & ) {
for (i = ; i < len; i++) {
if ((unsigned char)c[i] <= ' ' &&
(c[i] == ' ' || c[i] == '\n' || c[i] == '\r' || c[i] == '\t' || c[i] == '\v' || c[i] == '\0')) {
trimmed++;
} else {
break;
}
}
len -= trimmed;
c += trimmed;
}
if (mode & ) {
if (len > ) {
i = len - ;
do {
if ((unsigned char)c[i] <= ' ' &&
(c[i] == ' ' || c[i] == '\n' || c[i] == '\r' || c[i] == '\t' || c[i] == '\v' || c[i] == '\0')) {
len--;
} else {
break;
}
} while (i-- != );
}
}
} if (ZSTR_LEN(str) == len) {
return zend_string_copy(str);
} else {
return zend_string_init(c, len, );
}
}
/* }}} */

ltrim()、rtrim() 或 trim()的参数二(what)存在时进入15行处的分支,参数二不存在时进入68行处的分支。

没有参数二时,会去除空格、"\t"、"\n"、"\r"、"\0"、"\v"

即:(unsigned char)c[i] <= ' ' && (c[i] == ' ' || c[i] == '\n' || c[i] == '\r' || c[i] == '\t' || c[i] == '\v' || c[i] == '\0')

存在参数二时,会去除参数二中指定的字符。

其中函数 php_charmask() 用于处理 trim("abc123456fjsklsf", "a..z") 中 字符范围 a...z

 static inline int php_charmask(unsigned char *input, size_t len, char *mask)
{
unsigned char *end;
unsigned char c;
int result = SUCCESS; memset(mask, , );
for (end = input+len; input < end; input++) {
c=*input;
if ((input+ < end) && input[] == '.' && input[] == '.'
&& input[] >= c) {
memset(mask+c, , input[] - c + );
input+=;
} else if ((input+ < end) && input[] == '.' && input[] == '.') {
/* 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, E_WARNING, "Invalid '..'-range, no character to the left of '..'");
result = FAILURE;
continue;
}
if (input+ >= end) { /* there is no 'right' char */
php_error_docref(NULL, E_WARNING, "Invalid '..'-range, no character to the right of '..'");
result = FAILURE;
continue;
}
if (input[-] > input[]) { /* wrong order */
php_error_docref(NULL, 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, E_WARNING, "Invalid '..'-range");
result = FAILURE;
continue;
} else {
mask[c]=;
}
}
return result;
}

第二个参数是字符范围的时候,源码中并没有严格限制成 a..z 这样的格式。

总的流程就是,待处理的字符串左侧(或右侧)逐字符去匹配是否在将要去除的字符中(第二个参数设置的字符 或者 默认的那6个字符),

如果字符匹配到则进行下一个比较,否则中断匹配查找。返回余下字符串。

php内置函数分析之trim()的更多相关文章

  1. map内置函数分析所得到的思路

    map:会根据提供的函数对指定序列做映射. map(func, *iterables) --> map object Make an iterator that computes the fun ...

  2. php内置函数分析之array_diff_assoc()

    static void php_array_diff_key(INTERNAL_FUNCTION_PARAMETERS, int data_compare_type) /* {{{ */ { uint ...

  3. php内置函数分析之array_combine()

    PHP_FUNCTION(array_combine) { HashTable *values, *keys; uint32_t pos_values = ; zval *entry_keys, *e ...

  4. php内置函数分析之ucwords()

    PHP_FUNCTION(ucwords) { zend_string *str; char *delims = " \t\r\n\f\v"; register char *r, ...

  5. php内置函数分析之strtoupper()、strtolower()

    strtoupper(): PHP_FUNCTION(strtoupper) { zend_string *str; ZEND_PARSE_PARAMETERS_START(, ) Z_PARAM_S ...

  6. php内置函数分析之ucfirst()、lcfirst()

    ucfirst($str) 将 str 的首字符(如果首字符是字母)转换为大写字母,并返回这个字符串. 源码位于 ext/standard/string.c /* {{{ php_ucfirst Up ...

  7. php内置函数分析之str_pad()

    PHP_FUNCTION(str_pad) { /* Input arguments */ zend_string *input; /* Input string 输入字符串*/ zend_long ...

  8. php内置函数分析之array_fill_keys()

    PHP_FUNCTION(array_fill_keys) { zval *keys, *val, *entry; if (zend_parse_parameters(ZEND_NUM_ARGS(), ...

  9. php内置函数分析range()

    PHP_FUNCTION(range) { zval *zlow, *zhigh, *zstep = NULL, tmp; , is_step_double = ; double step = 1.0 ...

随机推荐

  1. sql server 高版本数据还原到低版本sql server的注意事项

    生成的sql脚本不能大于100m,否则会报错(System.OutOfMemory) 所以要将较大的sql脚本文件进行分割

  2. [CF46D]Parking Lot

    题目:Parking Lot 传送门:http://codeforces.com/problemset/problem/46/D 分析: 做法一: 1)这题和Hotel那题一样,也可以看做是求区间空位 ...

  3. GMM demo

    # GMM model # // library(mvtnorm) ) n1 = n2 = mu1 = c(,) mu2 = c(-,-) sigma1 = matrix(c(,.,.,),nrow= ...

  4. 架构-数据库访问-SQL语言进行连接数据库服务器-OLE:OLE

    ylbtech-架构-数据库访问-SQL语言进行连接数据库服务器-OLE:OLE Object Linking and Embedding,对象连接与嵌入,简称OLE技术.OLE 不仅是桌面应用程序集 ...

  5. java poi 导入导出Excel xsl xslx

    import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import  ...

  6. 阶段1 语言基础+高级_1-3-Java语言高级_1-常用API_1_第5节 String类_10_练习:统计输入的字符串中

    char类型在发生数学运算的时候,可以提升为int类型 这就表示char在A到Z之间的

  7. JAVA在页面查看或下载服务器上的日志

    1.配置 FileUtils类所需jar包的maven地址 <dependency> <groupId>commons-io</groupId> <artif ...

  8. VGA时序及其原理(转载)

    显示器扫描方式分为逐行扫描和隔行扫描:逐行扫描是扫描从屏幕左上角一点开始,从左像右逐点扫描,每扫描完一行,电子束回到屏幕的左边下一行的起始位置,在这期间,CRT对电子束进行消隐,每行结束时,用行同步信 ...

  9. xmake v2.1.9版本发布,增加可视化图形菜单配置

    此版本主要增加xmake f --menu实现用户自定义图形菜单配置,界面风格类似linux的make menuconfig: [图片上传失败-(image-505bc0-1517795319124) ...

  10. 毕业之后de经历

    毕业之后 2016年7月,我大学毕业了.7月3号到7月6号,我陆续用我的小行李箱,在半夜12点左右,把我的生活用品拉出宿舍,大汗淋漓之后,我就在晚上12点多,找个奶茶店买一杯芒果冰沙.白天要去厦门的一 ...