From 3e7eab350c4a6a2cf510be7ad7cd4cb086c11145 Mon Sep 17 00:00:00 2001 From: Alexander Borisov Date: Wed, 17 Jul 2019 14:24:00 +0300 Subject: [PATCH] Added support '$&' substitution in String.prototype.replace(). --- njs/njs_string.c | 25 ++++++++++++++----------- njs/test/njs_unit_test.c | 16 ++++++++++++---- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/njs/njs_string.c b/njs/njs_string.c index f2b65740..8031b70e 100644 --- a/njs/njs_string.c +++ b/njs/njs_string.c @@ -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; diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 94be56d7..00140ff4 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -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("/\\]/") }, -- 2.47.3