溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

php trim函數(shù)是怎樣實(shí)現(xiàn)的

發(fā)布時(shí)間:2022-02-04 13:13:25 來源:億速云 閱讀:127 作者:柒染 欄目:編程語言

這篇文章跟大家分析一下“php trim函數(shù)是怎樣實(shí)現(xiàn)的”。內(nèi)容詳細(xì)易懂,對“php trim函數(shù)是怎樣實(shí)現(xiàn)的”感興趣的朋友可以跟著小編的思路慢慢深入來閱讀一下,希望閱讀后能夠?qū)Υ蠹矣兴鶐椭?。下面跟著小編一起深入學(xué)習(xí)“php trim函數(shù)是怎樣實(shí)現(xiàn)的”的知識吧。

php trim函數(shù)的實(shí)現(xiàn)原理:1、定義一個(gè)len來存儲字符串的長度;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)號(.)
   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,它就會把a b c d 都去掉。因?yàn)槭÷蕴柕脑?,所?code>trim函數(shù)的第二個(gè)參數(shù)不能用..開頭或者結(jié)尾。

第二個(gè)問題:
再看一個(gè)例子:
php -r 'echo trim("abcdcba","abc")."\n";'
我的本意是將字符串abcdcba最前面的abc去掉保留dcba,但結(jié)果卻是這樣的:
d
也就是說他會把a b c分別去掉。這應(yīng)該算是個(gè)坑吧。

通過對底層源代碼的分析來說一下為什么會出現(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)。
剛開始就是定義了簡單的變量,再下面對變量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)建要去除的字符的哈希對應(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)備工作,后面的就是真正處理去除操作了。
通過源代碼可以看到,下面的操作先對mode這個(gè)變量做了判斷,那么mode這個(gè)變量是干嘛的?答案就是用來處理 ltrim rtirm trim3個(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的底層是怎么處理的。先對mode 分別取模,再做相應(yīng)的操作。
實(shí)際的去除操作就很簡單了。
定義一個(gè)len來存儲字符串的長度,c 是一個(gè)字符指針,剛開始從左邊開始去除,判斷c中的字符是否在hashmask中存在,如果存在,就將c 的指針向后移動一位,將len減去一位,如果發(fā)現(xiàn)*c的字符不存在于hashmask中,停止操作(可能和實(shí)際代碼邏輯不不一致,但思想師一樣的)。相關(guān)代碼如下:

for (i = 0; i

左邊操作完成以后,右邊的操作比較簡單,從*c最右邊開始匹配,如果匹配到,就將len的長度減1,如果沒有舊停止操作。相關(guān)的代碼如下:

for (i = len - 1; i >= 0; i--) {
    if (mask[(unsigned char)c[i]]) {
        len--;
    } else {
        break;
    }
}

最后就是一個(gè)簡單返回操,把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í)更多知識,請大家多多留意小編的更新。謝謝大家關(guān)注一下億速云網(wǎng)站!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI