pollita Thu Jan 30 00:00:42 2003 EDT Modified files: /php4/ext/standard basic_functions.c php_string.h string.c Log: Feature Request # 5919 - Addition of str_ireplace() Also removed deprecated BM str replace menthod Also rewrote php_str_to_str to use more processor/memory efficient method (ilia)
Index: php4/ext/standard/basic_functions.c diff -u php4/ext/standard/basic_functions.c:1.568 php4/ext/standard/basic_functions.c:1.569 --- php4/ext/standard/basic_functions.c:1.568 Tue Jan 28 19:49:09 2003 +++ php4/ext/standard/basic_functions.c Thu Jan 30 00:00:40 2003 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: basic_functions.c,v 1.568 2003/01/29 00:49:09 phanto Exp $ */ +/* $Id: basic_functions.c,v 1.569 2003/01/30 05:00:40 pollita Exp $ */ #include "php.h" #include "php_streams.h" @@ -361,6 +361,7 @@ PHP_FE(addcslashes, NULL) PHP_FE(rtrim, NULL) PHP_FE(str_replace, NULL) + PHP_FE(str_ireplace, + NULL) PHP_FE(str_repeat, NULL) PHP_FE(count_chars, NULL) PHP_FE(chunk_split, NULL) Index: php4/ext/standard/php_string.h diff -u php4/ext/standard/php_string.h:1.68 php4/ext/standard/php_string.h:1.69 --- php4/ext/standard/php_string.h:1.68 Tue Jan 28 19:07:01 2003 +++ php4/ext/standard/php_string.h Thu Jan 30 00:00:40 2003 @@ -17,7 +17,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_string.h,v 1.68 2003/01/29 00:07:01 iliaa Exp $ */ +/* $Id: php_string.h,v 1.69 2003/01/30 05:00:40 pollita Exp $ */ /* Synced with php 3.0 revision 1.43 1999-06-16 [ssb] */ @@ -27,6 +27,7 @@ PHP_FUNCTION(strspn); PHP_FUNCTION(strcspn); PHP_FUNCTION(str_replace); +PHP_FUNCTION(str_ireplace); PHP_FUNCTION(rtrim); PHP_FUNCTION(trim); PHP_FUNCTION(ltrim); @@ -121,6 +122,8 @@ PHPAPI char *php_basename(char *str, size_t len , char *suffix, size_t sufflen); PHPAPI void php_dirname(char *str, int len); PHPAPI char *php_stristr(unsigned char *s, unsigned char *t, size_t s_len, size_t t_len); +PHPAPI char *php_str_to_str_ex(char *haystack, int length, char *needle, + int needle_len, char *str, int str_len, int *_new_length, int +case_sensitivity); PHPAPI char *php_str_to_str(char *haystack, int length, char *needle, int needle_len, char *str, int str_len, int *_new_length); PHPAPI char *php_trim(char *c, int len, char *what, int what_len, zval *return_value, int mode TSRMLS_DC); Index: php4/ext/standard/string.c diff -u php4/ext/standard/string.c:1.351 php4/ext/standard/string.c:1.352 --- php4/ext/standard/string.c:1.351 Fri Jan 24 08:18:08 2003 +++ php4/ext/standard/string.c Thu Jan 30 00:00:41 2003 @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: string.c,v 1.351 2003/01/24 13:18:08 andrey Exp $ */ +/* $Id: string.c,v 1.352 2003/01/30 05:00:41 pollita Exp $ */ /* Synced with php 3.0 revision 1.193 1999-06-16 [ssb] */ @@ -2668,83 +2668,105 @@ } /* }}} */ -/* {{{ boyer_str_to_str */ -static char *boyer_str_to_str(char *haystack, int length, - char *needle, int needle_len, char *str, - int str_len, int *new_length) -{ - char *p, *pe, *cursor, *end, *r; - int off; - char jump_table[256]; - smart_str result = {0}; +/* {{{ php_str_to_str_ex + */ +PHPAPI char *php_str_to_str_ex(char *haystack, int length, + char *needle, int needle_len, char *str, int str_len, int *_new_length, int +case_sensitivity) +{ + char *new_str; - /* - * We implement only the first half of the Boyer-Moore algorithm, - * because the second half is too expensive to compute during run-time. - * TODO: Split matching into compile-/match-stage. - */ - - /* Prepare the jump_table which contains the skip offsets */ - memset(jump_table, needle_len, 256); - - off = needle_len - 1; - - /* Calculate the default start where each comparison starts */ - pe = needle + off; + if (needle_len < length) { + char *end, *haystack_dup, *needle_dup; + char *e, *s, *p, *r; + + if (needle_len == str_len) { + new_str = estrndup(haystack, length); + *_new_length = length; + + if (case_sensitivity) { + end = new_str + length; + for (p = new_str; (r = php_memnstr(p, needle, +needle_len, end)); p = r + needle_len) { + memcpy(r, str, str_len); + } + } else { + haystack_dup = estrndup(haystack, length); + needle_dup = estrndup(needle, needle_len); + php_strtolower(haystack_dup, length); + php_strtolower(needle_dup, needle_len); + end = haystack_dup + length; + for (p = haystack_dup; (r = php_memnstr(p, needle_dup, +needle_len, end)); p = r + needle_len) { + memcpy(new_str + (r - haystack_dup), str, +str_len); + } + efree(haystack_dup); + efree(needle_dup); + } + return new_str; + } else { + if (str_len < needle_len) { + new_str = emalloc(length + 1); + } else { + new_str = emalloc((length / needle_len + 1) * str_len); + } + + e = s = new_str; + + if (case_sensitivity) { + end = haystack + length; + for (p = haystack; (r = 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; + } + + if (p < end) { + memcpy(e, p, end - p); + e += end - p; + } + } else { + haystack_dup = estrndup(haystack, length); + needle_dup = estrndup(needle, needle_len); + php_strtolower(haystack_dup, length); + php_strtolower(needle_dup, needle_len); + + end = haystack_dup + length; + + for (p = haystack_dup; (r = php_memnstr(p, needle_dup, +needle_len, end)); p = r + needle_len) { + memcpy(e, haystack + (p - haystack_dup), r - +p); + e += r - p; + memcpy(e, str, str_len); + e += str_len; + } - /* Assign skip offsets based on the pattern */ - for (p = needle; p <= pe; p++) - jump_table[(unsigned char) *p] = off--; - - /* Start to look at the first possible position for the pattern */ - cursor = haystack + needle_len - 1; - - /* The cursor must not cross this limit */ - end = haystack + length; - - /* Start to copy at haystack */ - r = haystack; - -nextiter: - while (cursor < end) { - p = pe; /* Compare from right to left */ - while (*p == *cursor) { - if (--p < needle) { /* Found the pattern */ - - /* Append whatever was not matched */ - smart_str_appendl(&result, r, cursor - r); - - /* Append replacement string */ - smart_str_appendl(&result, str, str_len); - - /* Update copy pointer */ - r = cursor + needle_len; - - /* needle_len was substracted from cursor for - * this comparison, add it back. Also add - * needle_len - 1 which is the default search - * offset. - */ - cursor += (needle_len << 1) - 1; - - /* Next iteration */ - goto nextiter; - } - cursor--; - } - - cursor += jump_table[(unsigned char) *cursor]; - } - - if (r < end) /* Copy the remaining data */ - smart_str_appendl(&result, r, end - r); + if (p < end) { + memcpy(e, haystack + (p - haystack_dup), end - +p); + e += end - p; + } + efree(haystack_dup); + efree(needle_dup); + } - smart_str_0(&result); /* NUL-ify result */ + *e = '\0'; + *_new_length = e - s; - if (new_length) - *new_length = result.len; + new_str = erealloc(new_str, *_new_length + 1); + return new_str; + } + } else if (needle_len > length) { +nothing_todo: + *_new_length = length; + new_str = estrndup(haystack, length); + return new_str; + } else { + if (case_sensitivity ? strncmp(haystack, needle, length) : +strncasecmp(haystack, needle, length)) { + goto nothing_todo; + } else { + *_new_length = str_len; + new_str = estrndup(str, str_len); + return new_str; + } + } - return result.c; } /* }}} */ @@ -2753,43 +2775,21 @@ PHPAPI char *php_str_to_str(char *haystack, int length, char *needle, int needle_len, char *str, int str_len, int *_new_length) { - char *p; - char *r; - char *end = haystack + length; - smart_str result = {0}; - - for (p = haystack; - (r = php_memnstr(p, needle, needle_len, end)); - p = r + needle_len) { - smart_str_appendl(&result, p, r - p); - smart_str_appendl(&result, str, str_len); - } - - if (p < end) - smart_str_appendl(&result, p, end - p); - - smart_str_0(&result); - - if (_new_length) - *_new_length = result.len; - - return result.c; -} -/* }}} */ + return php_str_to_str_ex(haystack, length, needle, needle_len, str, str_len, +_new_length, 1); +} +/* }}} + */ /* {{{ php_str_replace_in_subject */ -static void php_str_replace_in_subject(zval *search, zval *replace, zval **subject, zval *result, int boyer) +static void php_str_replace_in_subject(zval *search, zval *replace, zval **subject, +zval *result, int case_sensitivity) { zval **search_entry, **replace_entry = NULL, temp_result; char *replace_value = NULL; int replace_len = 0; - char *(*str_to_str)(char *, int, char *, int, char *, int, int *); - str_to_str = boyer ? boyer_str_to_str : php_str_to_str; - /* Make sure we're dealing with strings. */ convert_to_string_ex(subject); Z_TYPE_P(result) = IS_STRING; @@ -2851,9 +2851,9 @@ replace_len, &temp_result); } else if (Z_STRLEN_PP(search_entry) > 1) { - Z_STRVAL(temp_result) = str_to_str(Z_STRVAL_P(result), Z_STRLEN_P(result), - Z_STRVAL_PP(search_entry), Z_STRLEN_PP(search_entry), - replace_value, replace_len, &Z_STRLEN(temp_result)); + Z_STRVAL(temp_result) = +php_str_to_str_ex(Z_STRVAL_P(result), Z_STRLEN_P(result), + + Z_STRVAL_PP(search_entry), Z_STRLEN_PP(search_entry), + + replace_value, replace_len, &Z_STRLEN(temp_result), +case_sensitivity); } efree(Z_STRVAL_P(result)); @@ -2875,9 +2875,9 @@ Z_STRLEN_P(replace), result); } else if (Z_STRLEN_P(search) > 1) { - Z_STRVAL_P(result) = str_to_str(Z_STRVAL_PP(subject), Z_STRLEN_PP(subject), - Z_STRVAL_P(search), Z_STRLEN_P(search), - Z_STRVAL_P(replace), Z_STRLEN_P(replace), &Z_STRLEN_P(result)); + Z_STRVAL_P(result) = php_str_to_str_ex(Z_STRVAL_PP(subject), +Z_STRLEN_PP(subject), + + Z_STRVAL_P(search), Z_STRLEN_P(search), + + Z_STRVAL_P(replace), Z_STRLEN_P(replace), &Z_STRLEN_P(result), +case_sensitivity); } else { *result = **subject; zval_copy_ctor(result); @@ -2887,32 +2887,78 @@ } /* }}} */ -/* {{{ proto mixed str_replace(mixed search, mixed replace, mixed subject [, bool boyer]) +/* {{{ proto mixed str_replace(mixed search, mixed replace, mixed subject) Replaces all occurrences of search in haystack with replace */ PHP_FUNCTION(str_replace) { - zval **subject, **search, **replace, **subject_entry, **pboyer; + zval **subject, **search, **replace, **subject_entry; zval *result; char *string_key; uint string_key_len; ulong num_key; - int boyer = 0; - if (ZEND_NUM_ARGS() < 3 || - ZEND_NUM_ARGS() > 4 || - zend_get_parameters_ex(ZEND_NUM_ARGS(), &search, - &replace, &subject, &pboyer) == FAILURE) { + if (ZEND_NUM_ARGS() != 3 || + zend_get_parameters_ex(3, &search, &replace, &subject) == FAILURE) { WRONG_PARAM_COUNT; } - switch (ZEND_NUM_ARGS()) { - case 4: - convert_to_boolean_ex(pboyer); - if (Z_BVAL_PP(pboyer)) - boyer = 1; - break; + SEPARATE_ZVAL(search); + SEPARATE_ZVAL(replace); + SEPARATE_ZVAL(subject); + + /* Make sure we're dealing with strings and do the replacement. */ + if (Z_TYPE_PP(search) != IS_ARRAY) { + convert_to_string_ex(search); + convert_to_string_ex(replace); + } else if (Z_TYPE_PP(replace) != IS_ARRAY) { + convert_to_string_ex(replace); } - + + /* if subject is an array */ + if (Z_TYPE_PP(subject) == IS_ARRAY) { + array_init(return_value); + zend_hash_internal_pointer_reset(Z_ARRVAL_PP(subject)); + + /* For each subject entry, convert it to string, then perform +replacement + and add the result to the return_value array. */ + while (zend_hash_get_current_data(Z_ARRVAL_PP(subject), (void +**)&subject_entry) == SUCCESS) { + MAKE_STD_ZVAL(result); + php_str_replace_in_subject(*search, *replace, subject_entry, +result, 1); + /* Add to return array */ + switch (zend_hash_get_current_key_ex(Z_ARRVAL_PP(subject), +&string_key, + + &string_key_len, &num_key, 0, NULL)) { + case HASH_KEY_IS_STRING: + add_assoc_zval_ex(return_value, string_key, +string_key_len, result); + break; + + case HASH_KEY_IS_LONG: + add_index_zval(return_value, num_key, result); + break; + } + + zend_hash_move_forward(Z_ARRVAL_PP(subject)); + } + } else { /* if subject is not an array */ + php_str_replace_in_subject(*search, *replace, subject, return_value, +1); + } +} +/* }}} */ + +/* {{{ proto mixed str_ireplace(mixed search, mixed replace, mixed subject) + Replaces all occurrences of search in haystack with replace / case-insensitive */ +PHP_FUNCTION(str_ireplace) +{ + zval **subject, **search, **replace, **subject_entry; + zval *result; + char *string_key; + uint string_key_len; + ulong num_key; + + if (ZEND_NUM_ARGS() != 3 || + zend_get_parameters_ex(3, &search, &replace, &subject) == FAILURE) { + WRONG_PARAM_COUNT; + } + SEPARATE_ZVAL(search); SEPARATE_ZVAL(replace); SEPARATE_ZVAL(subject); @@ -2934,7 +2980,7 @@ and add the result to the return_value array. */ while (zend_hash_get_current_data(Z_ARRVAL_PP(subject), (void **)&subject_entry) == SUCCESS) { MAKE_STD_ZVAL(result); - php_str_replace_in_subject(*search, *replace, subject_entry, result, boyer); + php_str_replace_in_subject(*search, *replace, subject_entry, +result, 0); /* Add to return array */ switch (zend_hash_get_current_key_ex(Z_ARRVAL_PP(subject), &string_key, &string_key_len, &num_key, 0, NULL)) { @@ -2950,7 +2996,7 @@ zend_hash_move_forward(Z_ARRVAL_PP(subject)); } } else { /* if subject is not an array */ - php_str_replace_in_subject(*search, *replace, subject, return_value, boyer); + php_str_replace_in_subject(*search, *replace, subject, return_value, +0); } } /* }}} */
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php