]> granicus.if.org Git - php/commitdiff
- MFH preg_filter()
authorMarcus Boerger <helly@php.net>
Fri, 29 Aug 2008 12:13:54 +0000 (12:13 +0000)
committerMarcus Boerger <helly@php.net>
Fri, 29 Aug 2008 12:13:54 +0000 (12:13 +0000)
# As discussed with Lukas
# [DOC] check out the test

NEWS
ext/pcre/php_pcre.c
ext/pcre/tests/preg_filter.phpt [new file with mode: 0755]

diff --git a/NEWS b/NEWS
index df0413b90e50f73c595a976b8ecac8089afc1a9d..4e49f0d973ce51c9a8e66ba760df7d54475f51d3 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,7 @@ PHP                                                                        NEWS
   accessibility (like method_exists()). (Felipe)
 - Changed array_reduce() to allow mixed $initial (Christian Seiler)
 
+- Added function preg_filter() that does grep and replace in one go. (Marcus)
 - Added system independent realpath() implementation which caches intermediate
   directories in realpath-cache. (Dmitry)
 - Added optional clear_realpath_cache and filename parameters to
index ee25c3a0cfb8b72718e1bf6e5982fec5fb561f39..63012dc1c62d12f3a646976a4d0bdb4dd9669f68 100644 (file)
@@ -1196,7 +1196,7 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub
 
 /* {{{ php_replace_in_subject
  */
-static char *php_replace_in_subject(zval *regex, zval *replace, zval **subject, int *result_len, int limit, zend_bool is_callable_replace, int *replace_count TSRMLS_DC)
+static char *php_replace_in_subject(zval *regex, zval *replace, zval **subject, int *result_len, int limit, int is_callable_replace, int *replace_count TSRMLS_DC)
 {
        zval            **regex_entry,
                                **replace_entry = NULL,
@@ -1284,7 +1284,7 @@ static char *php_replace_in_subject(zval *regex, zval *replace, zval **subject,
 
 /* {{{ preg_replace_impl
  */
-static void preg_replace_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_callable_replace)
+static void preg_replace_impl(INTERNAL_FUNCTION_PARAMETERS, int is_callable_replace, int is_filter)
 {
        zval               **regex,
                                   **replace,
@@ -1298,8 +1298,7 @@ static void preg_replace_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_callabl
        char                    *string_key;
        ulong                    num_key;
        char                    *callback_name;
-       int                              replace_count=0;
-       int                             *replace_count_ptr=NULL; 
+       int                              replace_count=0, old_replace_count;
        
        /* Get function parameters and do error-checking. */
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ|lZ", &regex, &replace, &subject, &limit, &zcount) == FAILURE) {
@@ -1312,8 +1311,9 @@ static void preg_replace_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_callabl
        }
 
        SEPARATE_ZVAL(replace);
-       if (Z_TYPE_PP(replace) != IS_ARRAY && (Z_TYPE_PP(replace) != IS_OBJECT || !is_callable_replace))
+       if (Z_TYPE_PP(replace) != IS_ARRAY && (Z_TYPE_PP(replace) != IS_OBJECT || !is_callable_replace)) {
                convert_to_string_ex(replace);
+       }
        if (is_callable_replace) {
                if (!zend_is_callable(*replace, 0, &callback_name TSRMLS_CC)) {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Requires argument 2, '%s', to be a valid callback", callback_name);
@@ -1332,9 +1332,6 @@ static void preg_replace_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_callabl
        if (ZEND_NUM_ARGS() > 3) {
                limit_val = limit;
        }
-       if (ZEND_NUM_ARGS() > 4) {
-               replace_count_ptr =& replace_count;
-       }
                
        if (Z_TYPE_PP(regex) != IS_ARRAY)
                convert_to_string_ex(regex);
@@ -1348,10 +1345,12 @@ static void preg_replace_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_callabl
                   and add the result to the return_value array. */
                while (zend_hash_get_current_data(Z_ARRVAL_PP(subject), (void **)&subject_entry) == SUCCESS) {
                        SEPARATE_ZVAL(subject_entry);
-                       if ((result = php_replace_in_subject(*regex, *replace, subject_entry, &result_len, limit_val, is_callable_replace, replace_count_ptr TSRMLS_CC)) != NULL) {
-                               /* Add to return array */
-                               switch(zend_hash_get_current_key(Z_ARRVAL_PP(subject), &string_key, &num_key, 0))
-                               {
+                       old_replace_count = replace_count;
+                       if ((result = php_replace_in_subject(*regex, *replace, subject_entry, &result_len, limit_val, is_callable_replace, &replace_count TSRMLS_CC)) != NULL) {
+                               if (!is_filter || replace_count > old_replace_count) {
+                                       /* Add to return array */
+                                       switch(zend_hash_get_current_key(Z_ARRVAL_PP(subject), &string_key, &num_key, 0))
+                                       {
                                        case HASH_KEY_IS_STRING:
                                                add_assoc_stringl(return_value, string_key, result, result_len, 0);
                                                break;
@@ -1359,17 +1358,25 @@ static void preg_replace_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_callabl
                                        case HASH_KEY_IS_LONG:
                                                add_index_stringl(return_value, num_key, result, result_len, 0);
                                                break;
+                                       }
+                               } else {
+                                       efree(result);
                                }
                        }
                
                        zend_hash_move_forward(Z_ARRVAL_PP(subject));
                }
        } else {        /* if subject is not an array */
-               if ((result = php_replace_in_subject(*regex, *replace, subject, &result_len, limit_val, is_callable_replace, replace_count_ptr TSRMLS_CC)) != NULL) {
-                       RETVAL_STRINGL(result, result_len, 0);
+               old_replace_count = replace_count;
+               if ((result = php_replace_in_subject(*regex, *replace, subject, &result_len, limit_val, is_callable_replace, &replace_count TSRMLS_CC)) != NULL) {
+                       if (!is_filter || replace_count > old_replace_count) {
+                               RETVAL_STRINGL(result, result_len, 0);
+                       } else {
+                               efree(result);
+                       }
                }
        }
-       if (replace_count_ptr) {
+       if (ZEND_NUM_ARGS() > 4) {
                zval_dtor(*zcount);
                ZVAL_LONG(*zcount, replace_count);
        }
@@ -1377,19 +1384,27 @@ static void preg_replace_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool is_callabl
 }
 /* }}} */
 
-/* {{{ proto string preg_replace(mixed regex, mixed replace, mixed subject [, int limit [, int &count]])
+/* {{{ proto mixed preg_replace(mixed regex, mixed replace, mixed subject [, int limit [, int &count]])
    Perform Perl-style regular expression replacement. */
 static PHP_FUNCTION(preg_replace)
 {
-       preg_replace_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
+       preg_replace_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
 }
 /* }}} */
 
-/* {{{ proto string preg_replace_callback(mixed regex, mixed callback, mixed subject [, int limit [, int &count]])
+/* {{{ proto mixed preg_replace_callback(mixed regex, mixed callback, mixed subject [, int limit [, int &count]])
    Perform Perl-style regular expression replacement using replacement callback. */
 static PHP_FUNCTION(preg_replace_callback)
 {
-       preg_replace_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
+       preg_replace_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0);
+}
+/* }}} */
+
+/* {{{ proto mixed preg_filter(mixed regex, mixed replace, mixed subject [, int limit [, int &count]])
+   Perform Perl-style regular expression replacement and only return matches. */
+static PHP_FUNCTION(preg_filter)
+{
+       preg_replace_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
 }
 /* }}} */
 
@@ -1879,6 +1894,7 @@ static const zend_function_entry pcre_functions[] = {
        PHP_FE(preg_match_all,                  arginfo_preg_match_all)
        PHP_FE(preg_replace,                    arginfo_preg_replace)
        PHP_FE(preg_replace_callback,   arginfo_preg_replace_callback)
+       PHP_FE(preg_filter,                             arginfo_preg_replace)
        PHP_FE(preg_split,                              arginfo_preg_split)
        PHP_FE(preg_quote,                              arginfo_preg_quote)
        PHP_FE(preg_grep,                               arginfo_preg_grep)
diff --git a/ext/pcre/tests/preg_filter.phpt b/ext/pcre/tests/preg_filter.phpt
new file mode 100755 (executable)
index 0000000..f9f479b
--- /dev/null
@@ -0,0 +1,35 @@
+--TEST--
+preg_filter()
+--SKIPIF--
+<?php
+if (@preg_match_all('/./u', "", $matches) === false) {
+       die("skip no utf8 support in PCRE library");
+}
+?>
+--FILE--
+<?php
+
+$subject = array('1', 'a', '2', 'b', '3', 'A', 'B', '4');
+$pattern = array('/\d/', '/[a-z]/', '/[1a]/');
+$replace = array('A:$0', 'B:$0', 'C:$0');
+
+var_dump(preg_filter($pattern, $replace, $subject));
+
+?>
+===DONE===
+--EXPECT--
+array(6) {
+  [0]=>
+  string(5) "A:C:1"
+  [1]=>
+  string(5) "B:C:a"
+  [2]=>
+  string(3) "A:2"
+  [3]=>
+  string(3) "B:b"
+  [4]=>
+  string(3) "A:3"
+  [7]=>
+  string(3) "A:4"
+}
+===DONE===