熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> PHP編程 >> 正文

解析strtr函數的效率問題

2022-06-13   來源: PHP編程 

  最近經常要對字符串進行匹配和替換操作之前一般使用str_replace或者preg_replace據說strtr的效率不錯所以對比了一下

復制代碼 代碼如下:
$i = ;
$t = microtime(true);
for(;$i<;$i++)
{
$str = strtr(md($i) $p);
}
var_dump(microtime(true)$t); //
$t = microtime(true);
for(;$i<;$i++)
{
$str = preg_replace($p md($i));
}
var_dump(microtime(true)$t); //

  
結果顯示strtr的效率比preg_replace高約%左右
趁著周末查看了strtr的php源碼

復制代碼 代碼如下:
PHP_FUNCTION(strtr)
{
zval **str **from **to;
int ac = ZEND_NUM_ARGS();
//參數檢查(zend_get_parameters_ex函數定義在zend_apic文件中)
if (ac < || ac > || zend_get_parameters_ex(ac &str &from &to) == FAILURE) {
WRONG_PARAM_COUNT;
}
//參數檢查
if (ac == && Z_TYPE_PP(from) != IS_ARRAY) {
php_error_docref(NULL TSRMLS_CC E_WARNING "The second argument is not an array");
RETURN_FALSE;
}
convert_to_string_ex(str);
/* shortcut for empty string */
//宏Z_STRLEN_PP定義在zend_operatorsh
if (Z_STRLEN_PP(str) == ) {
RETURN_EMPTY_STRING();
}
if (ac == ) {
php_strtr_array(return_value Z_STRVAL_PP(str) Z_STRLEN_PP(str) HASH_OF(*from));
} else {
convert_to_string_ex(from);
convert_to_string_ex(to);
ZVAL_STRINGL(return_value Z_STRVAL_PP(str) Z_STRLEN_PP(str) );
php_strtr(Z_STRVAL_P(return_value)
Z_STRLEN_P(return_value)
Z_STRVAL_PP(from)
Z_STRVAL_PP(to)
MIN(Z_STRLEN_PP(from)
Z_STRLEN_PP(to)));
}
}

  
先看看php_strtr函數

復制代碼 代碼如下:
//trlen是字符串str_from與str_to的長度的最小值
PHPAPI char *php_strtr(char *str int len char *str_from char *str_to int trlen)
{
int i;
unsigned char xlat[]; //
if ((trlen < ) || (len < )) {
return str;
}
//xlat的下標與值相等
for (i = ; i < ; xlat[i] = i i++);
//把from到to字符串的每一個字符對應起來例如from="ab"to="cd"則會產生這樣的對應a=>c b=>d
for (i = ; i < trlen; i++) {
xlat[(unsigned char) str_from[i]] = str_to[i];
}
//替換(不過覺得這個函數的效率還有可以改進的地方因為如果需要替換的字符只是占整個字符串很少的部分這樣就有大部分的賦值操作其實並沒有什麼意義這樣的情況下感覺先判斷再賦值感覺會高效一點有空測試一下)
for (i = ; i < len; i++) {
str[i] = xlat[(unsigned char) str[i]];
}
return str;
}

  
可見在處理strtr(abcdaaabcd ab efd)這樣的操作時應該是很高效的
(注意這個操作輸出efcdeeefcd)
再看看php_strtr_array

復制代碼 代碼如下:

  
static void php_strtr_array(zval *return_value char *str int slen HashTable *hash)
{
zval **entry;
char *string_key;
uint string_key_len;
zval **trans;
zval ctmp;
ulong num_key;
int minlen = *;
int maxlen = pos len found;
char *key;
HashPosition hpos;
smart_str result = {};
HashTable tmp_hash;
//把替換數組從hash復制到tmp_hash並記錄下標字符串的最大和最小長度
zend_hash_init(&tmp_hash NULL NULL );
zend_hash_internal_pointer_reset_ex(hash &hpos);
while (zend_hash_get_current_data_ex(hash (void **)&entry &hpos) == SUCCESS) {
switch (zend_hash_get_current_key_ex(hash &string_key &string_key_len &num_key &hpos)) {
case HASH_KEY_IS_STRING:
len = string_key_len;
if (len < ) {
zend_hash_destroy(&tmp_hash);
RETURN_FALSE;
}
zend_hash_add(&tmp_hash string_key string_key_len entry sizeof(zval*) NULL);
if (len > maxlen) {
maxlen = len;
}
if (len < minlen) {
minlen = len;
}
break;
//下標如果是整形的話會轉換成字符串類型例如array(=>aa)轉換成array(=>aa)
case HASH_KEY_IS_LONG:
Z_TYPE(ctmp) = IS_LONG;
Z_LVAL(ctmp) = num_key;
convert_to_string(&ctmp);
len = Z_STRLEN(ctmp);
zend_hash_add(&tmp_hash Z_STRVAL(ctmp) len+ entry sizeof(zval*) NULL);
zval_dtor(&ctmp);
if (len > maxlen) {
maxlen = len;
}
if (len < minlen) {
minlen = len;
}
break;
}
zend_hash_move_forward_ex(hash &hpos);
}
key = emalloc(maxlen+);
pos = ;
//從字符串的第一個字符開始循環匹配pos記錄當前查找的位置
while (pos < slen) {
//當前位置加上最大長度如果大於字符串長度則最大長度就需要改變
if ((pos + maxlen) > slen) {
maxlen = slen pos;
}
found = ;
memcpy(key str+pos maxlen);
//從最大長度開始匹配就是說對abcd若array(a=>eab=>f)則會先把ab替換為f而不是先把a換成e
for (len = maxlen; len >= minlen; len) {
key[len] = ;
//因為使用了hash表所以這樣的效率還是挺高的
if (zend_hash_find(&tmp_hash key len+ (void**)&trans) == SUCCESS) {
char *tval;
int tlen;
zval tmp;
if (Z_TYPE_PP(trans) != IS_STRING) {
tmp = **trans;
zval_copy_ctor(&tmp);
convert_to_string(&tmp);
tval = Z_STRVAL(tmp);
tlen = Z_STRLEN(tmp);
} else {
tval = Z_STRVAL_PP(trans);
tlen = Z_STRLEN_PP(trans);
}
//加入結果
smart_str_appendl(&result tval tlen);
//向前跳躍
pos += len;
found = ;
if (Z_TYPE_PP(trans) != IS_STRING) {
zval_dtor(&tmp);
}
break;
}
}
if (! found) {
smart_str_appendc(&result str[pos++]);
}
}
efree(key);
zend_hash_destroy(&tmp_hash);
smart_str_(&result);
RETVAL_STRINGL(resultc resultlen );
}


From:http://tw.wingwit.com/Article/program/PHP/201311/21131.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.