]> git.kaiwu.me - njs.git/commitdiff
Added support '$&' substitution in String.prototype.replace().
authorAlexander Borisov <alexander.borisov@nginx.com>
Wed, 17 Jul 2019 11:24:00 +0000 (14:24 +0300)
committerAlexander Borisov <alexander.borisov@nginx.com>
Wed, 17 Jul 2019 11:24:00 +0000 (14:24 +0300)
njs/njs_string.c
njs/test/njs_unit_test.c

index f2b65740f36ef3c2f9beacca4f6fa360588b55b1..8031b70e107eb366f95d4b6812ca23355d2fe967 100644 (file)
@@ -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 *vm, njs_string_replace_t *r,
             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 *vm, njs_string_replace_t *r,
                     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 *vm, njs_string_replace_t *r,
                  */
 
                 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 *vm, njs_string_replace_t *r,
         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;
index 94be56d71b4605fd4f514c1899a4545fe4e4e1f8..00140ff4a9a24329fa62a761ad95c0af2eeadee1 100644 (file)
@@ -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("/\\]/") },