這篇文章跟大家分析一下“php trim函數(shù)是怎樣實(shí)現(xiàn)的”。內(nèi)容詳細(xì)易懂,對(duì)“php trim函數(shù)是怎樣實(shí)現(xiàn)的”感興趣的朋友可以跟著小編的思路慢慢深入來閱讀一下,希望閱讀后能夠?qū)Υ蠹矣兴鶐椭O旅娓【幰黄鹕钊雽W(xué)習(xí)“php trim函數(shù)是怎樣實(shí)現(xiàn)的”的知識(shí)吧。
10年積累的做網(wǎng)站、網(wǎng)站建設(shè)經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶對(duì)網(wǎng)站的新想法和需求。提供各種問題對(duì)應(yīng)的解決方案。讓選擇我們的客戶得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站設(shè)計(jì)制作后付款的網(wǎng)站建設(shè)流程,更有四川免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。
php trim函數(shù)的實(shí)現(xiàn)原理:1、定義一個(gè)len來存儲(chǔ)字符串的長(zhǎng)度;2、判斷c中的字符是否在hashmask中存在;3、如果存在,將len減去一位;4、如果不存在則停止操作。
本文操作環(huán)境:Windows7系統(tǒng)、PHP7.1版、DELL G3電腦
php源碼分析trim函數(shù)的實(shí)現(xiàn)
在實(shí)際開發(fā)中遇到關(guān)于 trim
函數(shù)的2個(gè)問題:
1:使用trim
函數(shù)不能去除2個(gè)以上的連續(xù)點(diǎn)號(hào)(.)
2 : 使用trim
函數(shù)去除字符串的問題
先說一下第一個(gè)問題。
下面的一段代碼:
php -r "echo trim('abcdcba...','...');"
我的本意是要將字符串abcdcba...
最后三個(gè)點(diǎn)去掉,結(jié)果是報(bào)錯(cuò)。
PHP Warning: trim(): Invalid '..'-range, no character to the left of '..' in Command line code on line 1 Warning: trim(): Invalid '..'-range, no character to the left of '..' in Command line code on line 1 PHP Warning: trim(): Invalid '..'-range, no character to the right of '..' inCommand line code on line 1 Warning: trim(): Invalid '..'-range, no character to the right of '..' in Command line code on line 1
這個(gè)問題其實(shí)很好解釋,因?yàn)?trim
函數(shù)本書可以范圍操作,例如 如果trim
函數(shù)的第二個(gè)參數(shù) a..d
,它就會(huì)把a b c d
都去掉。因?yàn)槭÷蕴?hào)的原因,所以trim
函數(shù)的第二個(gè)參數(shù)不能用..
開頭或者結(jié)尾。
第二個(gè)問題:
再看一個(gè)例子:php -r 'echo trim("abcdcba","abc")."\n";'
我的本意是將字符串abcdcba
最前面的abc
去掉保留dcba
,但結(jié)果卻是這樣的:d
也就是說他會(huì)把a b c
分別去掉。這應(yīng)該算是個(gè)坑吧。
通過對(duì)底層源代碼的分析來說一下為什么會(huì)出現(xiàn)這2種情況。trim
函數(shù)的源代碼師在php
代碼根目錄開始的 ext/standard/string.c
函數(shù)的定義如下:
PHP_FUNCTION(trim) { php_do_trim(INTERNAL_FUNCTION_PARAM_PASSTHRU, 3); }
可以看到,定義調(diào)用了另外的函數(shù),函數(shù)體如下:
static void php_do_trim(INTERNAL_FUNCTION_PARAMETERS, int mode) { char *str; char *what = NULL; int str_len, what_len = 0; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRM\_CC, "s|s", &str, &str_len, &what, &what_len) == FAILURE) { return; } php_trim(str, str_len, what, what_len, return_value, mode TSRMLS_CC); }
zend_parse_parameters
函數(shù)的作用就是接受參數(shù),有興趣的同學(xué)可以查閱相關(guān)資料。從代碼可以看到,函數(shù)接受了2個(gè)字符串類型的參數(shù),一個(gè)str
,就是需要處理的字符串,第二個(gè)參數(shù)是what
,用來表示需要去除的字符。
這個(gè)函數(shù)在最后用調(diào)用了另外一個(gè)函數(shù),函數(shù)php_trim
,函數(shù)體如下:
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 = 0; i--) { if (mask[(unsigned char)c[i]]) { len--; } else { break; } } } if (return_value) { RETVAL_STRINGL(c, len, 1); } else { return estrndup(c, len); } return ""; }
這個(gè)函數(shù)就是php
真正處理去除操作的結(jié)構(gòu)。
剛開始就是定義了簡(jiǎn)單的變量,再下面對(duì)變量what
有一個(gè)判斷,來判斷是否傳遞了要去除的字符。可以看到,根據(jù)是不是傳遞了what
,函數(shù)傳遞給php_charmask
函數(shù)的參數(shù)不一樣,從這兒可以看出,如果trim
沒有傳要去除的字符,默認(rèn)情況是去除" \n\r\t\v\0"
六個(gè)字符的,下面來看看php_charmask
函數(shù)進(jìn)行了哪些操作。
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); for (end = input+len; input = c) { memset(mask+c, 1, input[3] - c + 1); input+=3; } else if ((input+1 = 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 { mask[c]=1; } } return result; }
這個(gè)函數(shù)的作用主要是,創(chuàng)建要去除的字符的哈希對(duì)應(yīng)關(guān)系,剛開始考慮了特殊情況像a..d
這樣的情況(從這兒也能看出來為什么trim
函數(shù)不能處理...
的情況)。后面就是建立hash
結(jié)構(gòu)的過程。最后的結(jié)果是一個(gè)數(shù)組,以要去除的字符是 abc
為例:
mask['a'] = 1; mask['b'] = 1; mask['c'] = 1;
這樣的hash結(jié)構(gòu),最后返回的就是這個(gè) mask
(實(shí)際沒有返回,使用引用變量傳值的方式做到數(shù)據(jù)的返回)
前面的都是準(zhǔn)備工作,后面的就是真正處理去除操作了。
通過源代碼可以看到,下面的操作先對(duì)mode
這個(gè)變量做了判斷,那么mode
這個(gè)變量是干嘛的?答案就是用來處理 ltrim rtirm trim
3個(gè)函數(shù)的。
下面師一段C語言代碼:
#includeint main(){ printf("%d\n",1&1); printf("%d\n",2&2); printf("%d\n",3&1); printf("%d\n",3&2); return 0; }
這段代碼的輸出結(jié)果如下:
1 2 1 2
通過這個(gè)大家可以看出來,trim
的底層是怎么處理的。先對(duì)mode
分別取模,再做相應(yīng)的操作。
實(shí)際的去除操作就很簡(jiǎn)單了。
定義一個(gè)len
來存儲(chǔ)字符串的長(zhǎng)度,c
是一個(gè)字符指針,剛開始從左邊開始去除,判斷c
中的字符是否在hashmask
中存在,如果存在,就將c
的指針向后移動(dòng)一位,將len
減去一位,如果發(fā)現(xiàn)*c
的字符不存在于hashmask
中,停止操作(可能和實(shí)際代碼邏輯不不一致,但思想師一樣的)。相關(guān)代碼如下:
for (i = 0; i
左邊操作完成以后,右邊的操作比較簡(jiǎn)單,從*c
最右邊開始匹配,如果匹配到,就將len
的長(zhǎng)度減1,如果沒有舊停止操作。相關(guān)的代碼如下:
for (i = len - 1; i >= 0; i--) { if (mask[(unsigned char)c[i]]) { len--; } else { break; } }
最后就是一個(gè)簡(jiǎn)單返回操,把c
指針現(xiàn)在指向的位置以后的len
個(gè)字符返回。實(shí)現(xiàn)返回的操作。整個(gè)過程完成。
相關(guān)代碼如下:
if (return_value) { RETVAL_STRINGL(c, len, 1); } else { return estrndup(c, len); }
關(guān)于php trim函數(shù)是怎樣實(shí)現(xiàn)的就分享到這里啦,希望上述內(nèi)容能夠讓大家有所提升。如果想要學(xué)習(xí)更多知識(shí),請(qǐng)大家多多留意小編的更新。謝謝大家關(guān)注一下創(chuàng)新互聯(lián)網(wǎng)站!