>백엔드 개발 >PHP 튜토리얼 >PHP에서 strtr 함수 사용에 대한 자세한 설명

PHP에서 strtr 함수 사용에 대한 자세한 설명

巴扎黑
巴扎黑원래의
2017-07-24 10:39:262326검색

strtr

문자열의 특정 문자를 변환하지만 이 함수는 다양한 방법으로 사용될 수 있습니다.

echo strtr('hello world', 'hw', 'ab'); // 第一种 aello borldecho strtr('hello world', 'hw', 'a'); // 第二种 aello worldecho strtr('hello world', ['hello' => 'hi']); // 第三种 hi worldecho strtr('hello world', ['he' => 'th', 'hello' => 'hi']); // 第四种 hi world


시간복잡도

O(n), 최악은 O(n*m)

소스코드

소스코드는 상황에 맞게 하나씩 분석됩니다.
첫 번째와 두 번째 유형도 가장 일반적으로 사용되는 유형이지만 두 번째 유형에서는 'h'만 'a'로 변환되고 'w'는 처리되지 않습니다. 이 대체 방법에서는 더 짧은 것이 우선합니다. from 및 to 중 하나가 빈 문자열인 경우 원래 문자열이 직접 반환됩니다.

RETURN_STR(php_strtr_ex(str,  Z_STRVAL_P(from),  to,          MIN(Z_STRLEN_P(from), to_len)));// 从源码MIN(Z_STRLEN_P(from), to_len))可以看出来,以from、to两个字符串短的为准,剩余的会被忽略掉,所以可以解释第二种情况'w'被忽略掉
// 同理,以下to中的'b'也会被忽略掉strtr('hello world', 'h', 'ab'); // aello world

다음으로 php_strtr_ex 메소드와 문자 변환 방법을 주로 살펴보겠습니다. 소스 코드는 해시 테이블을 사용하여 구현됩니다. 해시 테이블은 from의 각 문자를 to의 해당 문자에 매핑합니다.

static zend_string *php_strtr_ex(zend_string *str, char *str_from, char *str_to, size_t trlen)
{// trlen的值就是MIN(Z_STRLEN_P(from), to_len))
    // 先构建一个hash表,用php伪代码来解释第一种情况构建好的hash表
    // array('g'=>'g','h'=>'a','i'=>'i','w'=>'b')unsigned char xlat[256], j = 0;do { xlat[j] = j; } while (++j != 256);for (i = 0; i < trlen; i++) {
        xlat[(size_t)(unsigned char) str_from[i]] = str_to[i];
    }    // 接着遍历字符串,从hash表中找到转换的字符for (i = 0; i < ZSTR_LEN(str); i++) {if (ZSTR_VAL(str)[i] != xlat[(size_t)(unsigned char) ZSTR_VAL(str)[i]]) {
            new_str = zend_string_alloc(ZSTR_LEN(str), 0);
            memcpy(ZSTR_VAL(new_str), ZSTR_VAL(str), i);// 从hash表中找到转换的字符ZSTR_VAL(new_str)[i] = xlat[(size_t)(unsigned char) ZSTR_VAL(str)[i]];break;
        }
    }for (;i < ZSTR_LEN(str); i++) {// 从hash表中找到转换的字符ZSTR_VAL(new_str)[i] = xlat[(size_t)(unsigned char) ZSTR_VAL(str)[i]];
    }
}


세 번째와 네 번째 from은 배열입니다. from이 배열인 경우 상황은 일대일 문자 변환이 아니라 전체 키 문자열을 변환하는 문자열 대 문자열 변환입니다. 값 문자열로.

세 번째 유형인 from 배열에는 키-값 쌍이 하나만 있습니다. 구현 아이디어는 kmp 알고리즘에 따라 기본 문자열에서 키(교체된 문자열)의 위치를 ​​검색하는 것입니다. kmp 자체의 효율성은 O(n)이므로 문자열에서 m번을 대체하면 이 경우 strtr의 효율성은 O(n*m)이 됩니다

// 搜索被替换的字符串的所有位置e = s = ZSTR_VAL(new_str);end = ZSTR_VAL(haystack) + ZSTR_LEN(haystack);// php_memnstr搜索 被替换的字符串 的所有位置,并替换掉for (p = ZSTR_VAL(haystack); (r = (char*)php_memnstr(p, needle, needle_len, end)); p = r + needle_len) {
    memcpy(e, p, r - p);
    e += r - p;
    memcpy(e, str, str_len);
    e += str_len;
    (*replace_count)++;
}

네 번째 방법은 더 많은 것을 대체하는 것입니다. 배열 기준 문자열, 이것은 다양한 상황에서 가장 효율적이지 않습니다

// 先构造所有 被替换的字符串ZEND_HASH_FOREACH_STR_KEY(pats, str_key) {
    len = ZSTR_LEN(str_key);// 计算所有 被替换的字符串 最长和最短值if (len > maxlen) {
        maxlen = len;
    }if (len < minlen) {
        minlen = len;
    }// 记录每个key长度值的hash值num_bitset[len / sizeof(zend_ulong)] |= Z_UL(1) << (len % sizeof(zend_ulong));// 记录每个key首字符的hash值bitset[((unsigned char)ZSTR_VAL(str_key)[0]) / sizeof(zend_ulong)] |= Z_UL(1) << (((unsigned char)ZSTR_VAL(str_key)[0]) % sizeof(zend_ulong));
    
} ZEND_HASH_FOREACH_END();// 辅助两个hash表,替换的字符串old_pos = pos = 0;while (pos <= slen - minlen) {key = str + pos;// 如果从首字符的hash表匹配到,表示以key[0]字符开头的有可能是被替换的字符串if (bitset[((unsigned char)key[0]) / sizeof(zend_ulong)] & (Z_UL(1) << (((unsigned char)key[0]) % sizeof(zend_ulong)))) {
        len = maxlen;if (len > slen - pos) {
            len = slen - pos;
        }// key从maxlen循环到minlen,所以,第四种'hello'和'he',最先匹配到hellowhile (len >= minlen) {// 如果从长度hash表里面匹配到被替换的字符串里可能的长度,就从from数组里面找到替换的键值对zend_hash_str_findif ((num_bitset[len / sizeof(zend_ulong)] & (Z_UL(1) << (len % sizeof(zend_ulong))))) {
                entry = zend_hash_str_find(pats, key, len);if (entry != NULL) {
                    zend_string *s = zval_get_string(entry);
                    smart_str_appendl(&result, str + old_pos, pos - old_pos);
                    smart_str_append(&result, s);
                    old_pos = pos + len;pos = old_pos - 1;
                    zend_string_release(s);break;
                }
            }
            len--;
        }
    }pos++;
}

이 상황은 약간 복잡합니다. 다음 PHP 의사 코드는 위의 C 언어 코드를 번역합니다

$bitset = array_fill(0, 255, 0); // 首字符的hash表$num_bitset = array_fill(0, 255, 0); 
// key长度值的hash值$min_len = PHP_INT_MAX;$max_len = 0;$len = 0;
// echo strtr(&#39;hello world&#39;, [&#39;he&#39; => 'th', 'hello' => 'hi']);
$pats = ['he', 'hello'];
foreach($pats as $v){$len = strlen($v);if($len > $max_len) {$max_len = $len;
    }
    if($len < $min_len) {$min_len = $len;
    }
    $num_bitset[intdiv($len,8)] |= 1 << ($len%8);$bitset[intdiv(ord($v[0]),8)] |= 1 << (ord($v[0])%8);
}// print_r(array_unique($num_bitset));
// print_r(array_unique($bitset));
// 例如我们匹配hello,首字符是h,长度5
// 以下两行就是以上C语言的while循环里面两个if判断echo $bitset[intdiv(ord('h'),8)] & 1 << (ord('h')%8),PHP_EOL;echo $num_bitset[intdiv(5,8)] & 1 << (5%8),PHP_EOL;

위 내용은 PHP에서 strtr 함수 사용에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.