PHP source code reading strtr, php source code strtr

Source: Internet
Author: User

PHP source code reading strtr, php source code strtr
Strtr

Converts specific characters in a string. However, this function can be used in many ways.

Echo strtr ('Hello world', 'hw ',' AB '); // aello borldecho strtr ('Hello world', 'hw', 'A '); // aello worldecho strtr ('Hello world', ['hello' => 'Hi']); // The third type is hi worldecho strtr ('Hello world ', ['H' => 'th', 'Hello' => 'Hi']); // type 4 hi world


Time Complexity

O (n), the worst is O (n * m)

Source code

The source code is analyzed one by one based on each situation.
The first and second types are also the most commonly used, but the second type only converts 'H' to 'A', and 'w' is not processed. The replacement of this method is subject to the shorter party. If one of the from and to is an empty string, the original string is directly returned.

RETURN_STR (php_strtr_ex (str, Z_STRVAL_P (from), to, MIN (Z_STRLEN_P (from), to_len); // from source code MIN (Z_STRLEN_P (from), to_len )) it can be seen that the two strings from and to are short, and the remaining strings are ignored. Therefore, it can be explained that 'W' is ignored in the second case. // likewise, 'B' in the following to will also be ignored strtr ('Hello world', 'h', 'AB'); // aello world

 

Next, let's take a look at how the php_strtr_ex method achieves character conversion. The source code is implemented using the hash table. The hash table maps each character of the from to the corresponding location.

Static zend_string * php_strtr_ex (zend_string * str, char * str_from, char * str_to, size_t trlen) {// The value of trlen is MIN (Z_STRLEN_P (from), to_len )) // create a hash table first and use php pseudo code to explain the hash table created in the first case // 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];} // traverse the string and find the converted character for (I = 0; I <ZSTR_LEN (str); I ++) {if (ZSTR_VAL (str) from the hash table) [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); // find the converted character ZSTR_VAL (new_str) [I] = xlat [(size_t) (unsigned char) ZSTR_VAL (str) from the hash table) [I]; break ;}}for (; I <ZSTR_LEN (str); I ++) {// find the converted character ZSTR_VAL (new_str) from the hash table) [I] = xlat [(size_t) (unsigned char) ZSTR_VAL (str) [I];}

 


The third and fourth types of from are arrays. If the from is an array, it is not a one-to-one conversion, but a String Conversion, converts the entire key string to a value string.

Third, the from array has only one key-value pair. The implementation idea is to search for the key (Replaced string) position in the master string based on the kmp algorithm, replace the value. The kmp efficiency is O (n), So if m replacement is performed in the string, the strtr efficiency will be O (n * m)

// Search all locations of the replaced string. e = s = ZSTR_VAL (new_str); end = ZSTR_VAL (haystack) + ZSTR_LEN (haystack ); // php_memnstr search all the positions of the string to be replaced and replace 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) ++ ;}

 

Fourth, replace multiple strings with arrays, which is the most efficient in various situations.

// Construct all replaced strings ZEND_HASH_FOREACH_STR_KEY (pats, str_key) {len = ZSTR_LEN (str_key ); // calculate the longest and shortest values of all replaced strings if (len> maxlen) {maxlen = len;} if (len <minlen) {minlen = len ;} // record the hash value of each key length value num_bitset [len/sizeof (zend_ulong)] | = Z_UL (1) <(len % sizeof (zend_ulong )); // record the hash value of the first character of each key. 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 (); // two hash tables are supported. The replaced string old_pos = pos = 0; while (pos <= slen-minlen) {key = str + pos; // If the hash table matches from the first character, it indicates that the string starting with key [0] may be replaced by 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;} // The key loops from maxlen to minlen The fourth 'hello' and 'hes' are used to match hello while (len> = minlen) first) {// If the length from the hash table matches the possible length of the string to be replaced, find the replaced key value pair zend_hash_str_find if (num_bitset [len/sizeof (zend_ulong)] & (Z_UL (1) from the from Array) <(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 ++ ;}

 


This situation is a bit complicated. The following php pseudocode translates the above C language code.

$ Bitset = array_fill (0,255, 0); // hash table with the first character $ num_bitset = array_fill (0,255, 0); // hash value of the key length value $ min_len = PHP_INT_MAX; $ max_len = 0; $ len = 0; // echo strtr ('Hello world', ['hes' => 'th ', 'Hello' => 'Hi']); $ pats = ['hes', '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); // For example, if we match hello, the first character is h, the length is 5 // The following two rows are in the while loop of the C language above. The two if statements are used to determine echo $ bitset [intdiv (ord ('H'), 8)]. & 1 <(ord ('H') % 8), PHP_EOL; echo $ num_bitset [intdiv (5, 8)] & 1 <(5% 8), PHP_EOL;

Link to this article: JC blog-PHP source code reading strtr

Original article, reprinted please indicate the source

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.