From 5f1403e043fee9c52140a6508911ddadf64a36e3 Mon Sep 17 00:00:00 2001 From: xiboon <38988733+xiboon@users.noreply.github.com> Date: Wed, 3 Jul 2024 13:49:34 +0200 Subject: [PATCH 1/2] Added string.replace() and .replaceAll() --- devs/run-tests/05strings.ts | 13 +++++++++++++ packages/core/src/corelib.d.ts | 22 +++++++++++++++++----- packages/core/src/string.ts | 30 ++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/devs/run-tests/05strings.ts b/devs/run-tests/05strings.ts index ed4fb2d665..cd00dd3539 100644 --- a/devs/run-tests/05strings.ts +++ b/devs/run-tests/05strings.ts @@ -128,9 +128,22 @@ function testSplit() { isEq(sq3[2], "c,d") } +function testReplace() { + const q = "a,b,c,d" + const sq = q.replace(",", ":") + isEq(sq, "a:b,c,d") +} +function testReplaceAll() { + const q = "a,b,c,d" + const sq = q.replaceAll(",", ":") + isEq(sq, "a:b:c:d") +} + testStrings() testStringOps() consStringTest() testSlice() testSplit() +testReplace() +testReplaceAll() diff --git a/packages/core/src/corelib.d.ts b/packages/core/src/corelib.d.ts index 2a1e80e54f..4fa1ca1757 100644 --- a/packages/core/src/corelib.d.ts +++ b/packages/core/src/corelib.d.ts @@ -113,7 +113,19 @@ interface String { * If this value is not specified, the substring continues to the end of stringObj. */ slice(start?: number, end?: number): string + /** + * Replace the first instance of a substring in a string, using a search string. + * @param searchValue The substring to search for. + * @param replaceValue The string containing the text to replace the matched substring. + */ + replace(searchValue: string, replaceValue: string): string + /** + * Replace all instances of a substring in a string, using a search string. + * @param searchValue The substring to search for. + * @param replaceValue The string containing the text to replace all the matches found. + */ + replaceAll(searchValue: string, replaceValue: string): string /** Returns the length of a String object. */ readonly length: number @@ -440,7 +452,7 @@ interface Array { /** * Returns an iterable of keys in the array */ - keys(): IterableIterator; + keys(): IterableIterator } interface ArrayConstructor { @@ -725,10 +737,10 @@ declare var Promise: PromiseConstructor type Awaited = T extends null | undefined ? T // special case for `null | undefined` when not in `--strictNullChecks` mode : T extends object & { then(onfulfilled: infer F, ...args: infer _): any } // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped - ? F extends (value: infer V, ...args: infer _) => any // if the argument to `then` is callable, extracts the first argument - ? Awaited // recursively unwrap the value - : never // the argument to `then` was not callable - : T // non-object or non-thenable + ? F extends (value: infer V, ...args: infer _) => any // if the argument to `then` is callable, extracts the first argument + ? Awaited // recursively unwrap the value + : never // the argument to `then` was not callable + : T // non-object or non-thenable // utility types diff --git a/packages/core/src/string.ts b/packages/core/src/string.ts index 1ff8a5bebf..9e92b7627c 100644 --- a/packages/core/src/string.ts +++ b/packages/core/src/string.ts @@ -109,6 +109,36 @@ String.prototype.split = function ( return A } +String.prototype.replace = function ( + this: string, + searchValue: string, + replaceValue: string +): string { + const match = this.indexOf(searchValue) + if (match === -1) return this + return ( + this.slice(0, match) + + replaceValue + + this.slice(match + searchValue.length) + ) +} + +String.prototype.replaceAll = function ( + this: string, + searchValue: string, + replaceValue: string +): string { + let resultString = this + let match = this.indexOf(searchValue) + while (match !== -1) { + resultString = + resultString.slice(0, match) + + replaceValue + + resultString.slice(match + searchValue.length) + match = resultString.indexOf(searchValue) + } + return resultString +} function splitMatch(S: string, q: number, R: string): number { return S.indexOf(R, q, q + 1) === q ? q + R.length : -1 } From 9836d90911059310896b2dd35611c2c2c3037a61 Mon Sep 17 00:00:00 2001 From: xiboon <38988733+xiboon@users.noreply.github.com> Date: Wed, 3 Jul 2024 17:12:59 +0200 Subject: [PATCH 2/2] Fix bug where replaceAll could loop forever until OOM, and add tests --- devs/run-tests/05strings.ts | 7 +++++++ packages/core/src/string.ts | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/devs/run-tests/05strings.ts b/devs/run-tests/05strings.ts index cd00dd3539..943a275008 100644 --- a/devs/run-tests/05strings.ts +++ b/devs/run-tests/05strings.ts @@ -132,11 +132,18 @@ function testReplace() { const q = "a,b,c,d" const sq = q.replace(",", ":") isEq(sq, "a:b,c,d") + const q2 = "a,b,c,d" + const sq2 = q2.replace("c,d", "c,d,e,f") + isEq(sq2, "a,b,c,d,e,f") } + function testReplaceAll() { const q = "a,b,c,d" const sq = q.replaceAll(",", ":") isEq(sq, "a:b:c:d") + const q2 = "a,b,c,d,c,d" + const sq2 = q2.replaceAll("c,d", "c,d,e,f") + isEq(sq2, "a,b,c,d,e,f,c,d,e,f") } testStrings() diff --git a/packages/core/src/string.ts b/packages/core/src/string.ts index 9e92b7627c..74d9c6e477 100644 --- a/packages/core/src/string.ts +++ b/packages/core/src/string.ts @@ -132,10 +132,10 @@ String.prototype.replaceAll = function ( let match = this.indexOf(searchValue) while (match !== -1) { resultString = - resultString.slice(0, match) + - replaceValue + - resultString.slice(match + searchValue.length) - match = resultString.indexOf(searchValue) + resultString.slice(0, match) + + replaceValue + + resultString.slice(match + searchValue.length) + match = resultString.indexOf(searchValue, match + replaceValue.length) } return resultString }