[njs] Added support '$&' substitution in String.prototype.replace().

Alexander Borisov alexander.borisov at nginx.com
Wed Jul 17 15:21:26 UTC 2019


details:   https://hg.nginx.org/njs/rev/0960f0568b94
branches:  
changeset: 1057:0960f0568b94
user:      Alexander Borisov <alexander.borisov at nginx.com>
date:      Wed Jul 17 14:24:00 2019 +0300
description:
Added support '$&' substitution in String.prototype.replace().

diffstat:

 njs/njs_string.c         |  25 ++++++++++++++-----------
 njs/test/njs_unit_test.c |  16 ++++++++++++----
 2 files changed, 26 insertions(+), 15 deletions(-)

diffs (119 lines):

diff -r 377db9ae390d -r 0960f0568b94 njs/njs_string.c
--- a/njs/njs_string.c	Wed Jul 17 16:28:30 2019 +0300
+++ b/njs/njs_string.c	Wed Jul 17 14:24:00 2019 +0300
@@ -3516,6 +3516,9 @@ skip:
         } else if (c == '`') {
             type = NJS_SUBST_PRECEDING;
 
+        } else if (c == '&') {
+            type = 0;
+
         } else if (c == '\'') {
             type = NJS_SUBST_FOLLOWING;
 
@@ -3540,12 +3543,13 @@ static njs_ret_t
 njs_string_replace_substitute(njs_vm_t *vm, njs_string_replace_t *r,
     int *captures)
 {
-    uint32_t                   i, n, last, index;
+    int                        *capture;
+    uint32_t                   i, n, last;
     const u_char               *end;
     njs_string_subst_t         *s;
     njs_string_replace_part_t  *part, *subject;
 
-    index = 0;
+    capture = NULL;
 
     last = r->substitutions->items;
     end = r->part[0].start + r->part[0].size;
@@ -3607,15 +3611,14 @@ njs_string_replace_substitute(njs_vm_t *
             break;
 
         /*
-         * "$n" substitutions.
-         * "$&" is the same as "$0", the "$0" however is not supported.
+         * "$n" and "$&" substitutions.
          */
         default:
             if (captures[n] == captures[n + 1]) {
 
                 /* Empty match. */
 
-                if (captures[n - 1] == captures[n]) {
+                if (n > 0 && captures[n - 1] == captures[n]) {
 
                     /*
                      * Consecutive empty matches as in
@@ -3626,11 +3629,11 @@ njs_string_replace_substitute(njs_vm_t *
                     break;
                 }
 
-                index = n;
+                capture = &captures[n];
                 continue;
             }
 
-            if (index != 0) {
+            if (capture != NULL) {
 
                 /*
                  * Inserting a single character after a series of
@@ -3638,14 +3641,14 @@ njs_string_replace_substitute(njs_vm_t *
                  */
 
                 if (part->start < end) {
-                    part->start = r->part[0].start + captures[index];
+                    part->start = r->part[0].start + *capture;
                     part->size = nxt_utf8_next(part->start, end) - part->start;
 
                 } else {
                     part->size = 0;
                 }
 
-                index = 0;
+                capture = NULL;
                 break;
             }
 
@@ -3658,8 +3661,8 @@ njs_string_replace_substitute(njs_vm_t *
         part++;
     }
 
-    if (index != 0) {
-        part->start = r->part[0].start + captures[index];
+    if (capture != NULL) {
+        part->start = r->part[0].start + *capture;
 
         if (part->start < end) {
             part->size = nxt_utf8_next(part->start, end) - part->start;
diff -r 377db9ae390d -r 0960f0568b94 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Wed Jul 17 16:28:30 2019 +0300
+++ b/njs/test/njs_unit_test.c	Wed Jul 17 14:24:00 2019 +0300
@@ -5681,14 +5681,22 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("'abc'.replace(/(a*)/g, function v0() {return '124'})"),
       nxt_string("124124b124c124") },
 
-    { nxt_string("typeof '0'.replace(/^/g, '$0')"),
-      nxt_string("string") },
+    { nxt_string("'abc'.replace(/b/g, '$0')"),
+      nxt_string("a$0c") },
 
     { nxt_string("typeof String.bytesFrom(Array(15).fill(0xE3)).replace(/^/g, 1)"),
       nxt_string("string") },
 
-    { nxt_string("typeof '0'.replace(/^/g, '$&')"),
-      nxt_string("string") },
+#if 0 /* FIXME: PCRE limitation */
+    { nxt_string("'abc'.replace(/^/g, '|$&|')"),
+      nxt_string("||abc") },
+#endif
+
+    { nxt_string("'abc'.replace(/b/g, '|$&|')"),
+      nxt_string("a|b|c") },
+
+    { nxt_string("'ABC'.replace(/((A)B)/g, '($1|$&|$2)')"),
+      nxt_string("(AB|AB|A)C") },
 
     { nxt_string("/]/"),
       nxt_string("/\\]/") },


More information about the nginx-devel mailing list