diff --git a/docs/functions.md b/docs/functions.md index 4252088..6fe7025 100644 --- a/docs/functions.md +++ b/docs/functions.md @@ -406,6 +406,17 @@ replaceArray('?', ['8:30', '9:00'], 'The event will take place between ? and ?') // 'The event will take place between 8:30 and 9:00' ``` + +### replaceEnd + +The `replaceEnd` function replaces the last occurrence of the given value only if the value appears at the start of the string: + +```js +replaceEnd('World', 'Laravel', 'Hello World'); + +// Hello Laravel +``` + ### replaceFirst The `replaceFirst` function replaces the first occurrence of a given value in a string: ```js @@ -421,6 +432,16 @@ replaceLast('the', 'a', 'the quick brown fox jumps over the lazy dog'); // 'the quick brown fox jumps over a lazy dog' ``` +### replaceStart + +The `replaceStart` function replaces the first occurrence of the given value only if the value appears at the start of the string: + +```js +replaceStart('Hello', 'Laravel', 'Hello World'); + +// Laravel World +``` + You may also pass `false` as a third parameter to ignore case when removing strings. ### reverse The `reverse` function reverses the given string: diff --git a/docs/methods.md b/docs/methods.md index 7120078..3a2a903 100644 --- a/docs/methods.md +++ b/docs/methods.md @@ -562,6 +562,17 @@ Stringable.of('The event will take place between ? and ?').replaceArray('?', ['8 // 'The event will take place between 8:30 and 9:00' ``` + +### replaceEnd + +The `replaceEnd` method replaces the last occurrence of the given value only if the value appears at the start of the string: + +```js +Stringable.of('Hello World').replaceEnd('World', 'Laravel'); + +// Hello Laravel +``` + ### replaceFirst The `replaceFirst` method replaces the first occurrence of a given value in a string: ```js @@ -576,6 +587,17 @@ Stringable.of('the quick brown fox jumps over the lazy dog').replaceLast('the', // 'the quick brown fox jumps over a lazy dog' ``` + +### replaceStart + +The `replaceStart` method replaces the first occurrence of the given value only if the value appears at the start of the string: + +```js +Stringable.of('Hello World').replaceStart('Hello', 'Laravel'); + +// Laravel World +``` + ### replaceMatches The `replaceMatches` method replaces all portions of a string matching a pattern with the given replacement string: ```js diff --git a/docs/statics.md b/docs/statics.md index 5343ef2..4bfad90 100644 --- a/docs/statics.md +++ b/docs/statics.md @@ -442,6 +442,17 @@ Str.replace('6.x', '7.x', 'Laravel 6.x'); // 'Laravel 7.x' ``` + +### replaceEnd + +The `replaceEnd` function replaces the last occurrence of the given value only if the value appears at the start of the string: + +```js +Str.replaceEnd('World', 'Laravel', 'Hello World'); + +// Hello Laravel +``` + ### replaceFirst The `replaceFirst` function replaces the first occurrence of a given value in a string: ```js @@ -456,6 +467,17 @@ Str.replaceLast('the', 'a', 'the quick brown fox jumps over the lazy dog'); // 'the quick brown fox jumps over a lazy dog' ``` + +### replaceStart + +The `replaceStart` function replaces the first occurrence of the given value only if the value appears at the start of the string: + +```js +Str.replaceStart('Hello', 'Laravel', 'Hello World'); + +// Laravel World +``` + ### remove The `remove` function removes the given value or array of values from the string: ```js diff --git a/src/Str.ts b/src/Str.ts index 59a8655..b80e814 100644 --- a/src/Str.ts +++ b/src/Str.ts @@ -36,8 +36,10 @@ import { repeat, replaceArray, replace, + replaceEnd, replaceFirst, replaceLast, + replaceStart, remove, reverse, start, @@ -230,8 +232,10 @@ export const Str = { repeat, replaceArray, replace, + replaceEnd, replaceFirst, replaceLast, + replaceStart, remove, reverse, start, diff --git a/src/Stringable.ts b/src/Stringable.ts index f77b705..c377902 100644 --- a/src/Stringable.ts +++ b/src/Stringable.ts @@ -322,6 +322,12 @@ export class Stringable { return this; } + public replaceEnd = (search: string, replace: string): this => { + this._value = Str.replaceEnd(search, replace, this._value); + + return this; + } + public replaceFirst = (search: string, replace: string): this => { this._value = Str.replaceFirst(search, replace, this._value); @@ -334,6 +340,12 @@ export class Stringable { return this; } + public replaceStart = (search: string, replace: string): this => { + this._value = Str.replaceStart(search, replace, this._value); + + return this; + } + public replaceMatches = (pattern: RegExp | string, replace: string): this => { this._value = this._value.replace(new RegExp(pattern, 'g'), replace); diff --git a/src/methods.ts b/src/methods.ts index b666a00..80a9945 100644 --- a/src/methods.ts +++ b/src/methods.ts @@ -436,6 +436,18 @@ export const replace = (search: string | string[], replace: string | string[], s return subject; } +export const replaceEnd = (search: string, replace: string, subject: string): string => { + if (search === '') { + return subject; + } + + if (endsWith(subject, search)) { + return replaceLast(search, replace, subject); + } + + return subject; +} + export const replaceFirst = (search: string, replace: string, subject: string): string => { if (search === '') { return subject; @@ -460,6 +472,18 @@ export const replaceLast = (search: string, replace: string, subject: string): s return subject; } +export const replaceStart = (search: string, replace: string, subject: string): string => { + if (search === '') { + return subject; + } + + if (startsWith(subject, search)) { + return replaceFirst(search, replace, subject); + } + + return subject; +} + export const remove = (search: string | string[], subject: string, caseSensitive: boolean = true): string => { search = search instanceof Array ? search : [search]; diff --git a/tests/replaceEnd.test.js b/tests/replaceEnd.test.js new file mode 100644 index 0000000..70a7e39 --- /dev/null +++ b/tests/replaceEnd.test.js @@ -0,0 +1,35 @@ +'use strict'; + +const {Stringable} = require('../src/Stringable'); +const {Str} = require('../src/Str'); +const {replaceEnd} = require('../src/methods'); + +test.each([ + ['World', 'Laravel', 'Hello World', 'Hello Laravel'], + ['Hello', 'Laravel', 'Hello World', 'Hello World'], + ['bar', 'qux', 'foobar foobar', 'foobar fooqux'], + ['bar?', 'qux?', 'foo/bar? foo/bar?', 'foo/bar? foo/qux?'], + ['bar', '', 'foobar foobar', 'foobar foo'], + ['xxx', 'yyy', 'foobar foobar', 'foobar foobar'], + ['', 'yyy', 'foobar foobar', 'foobar foobar'], + ['xxx', 'yyy', 'fooxxx foobar', 'fooxxx foobar'], + ['ö', 'xxx', 'Malmö Jönköping', 'Malmö Jönköping'], + ['öping', 'yyy', 'Malmö Jönköping', 'Malmö Jönkyyy'], +])('.replaceEnd from %p search %p and replace with %p then returns %p', + /** + * @param {string} search + * @param {string} replace + * @param {string} string + * @param {string} expected + */ + (search, replace, string, expected) => { + expect(Stringable.of(string).replaceEnd(search, replace).toString()) + .toBe(expected); + + expect(Str.replaceEnd(search, replace, string)) + .toBe(expected); + + expect(replaceEnd(search, replace, string)) + .toBe(expected); + } +); diff --git a/tests/replaceStart.test.js b/tests/replaceStart.test.js new file mode 100644 index 0000000..9cf4f33 --- /dev/null +++ b/tests/replaceStart.test.js @@ -0,0 +1,35 @@ +'use strict'; + +const {Stringable} = require('../src/Stringable'); +const {Str} = require('../src/Str'); +const {replaceStart} = require('../src/methods'); + +test.each([ + ['Hello', 'Laravel', 'Hello World', 'Laravel World'], + ['World', 'Laravel', 'Hello World', 'Hello World'], + ['bar', 'qux', 'foobar foobar', 'foobar foobar'], + ['bar?', 'qux?', 'foo/bar? foo/bar?', 'foo/bar? foo/bar?'], + ['foo', 'qux', 'foobar foobar', 'quxbar foobar'], + ['foo/bar?', 'qux?', 'foo/bar? foo/bar?', 'qux? foo/bar?'], + ['foo', '', 'foobar foobar', 'bar foobar'], + [0, '1', '0', '1'], + ['Jö', 'xxx', 'Jönköping Malmö', 'xxxnköping Malmö'], + ['', 'yyy', 'Jönköping Malmö', 'Jönköping Malmö'], +])('.replaceEnd from %p search %p and replace with %p then returns %p', + /** + * @param {string} search + * @param {string} replace + * @param {string} subject + * @param {string} expected + */ + (search, replace, subject, expected) => { + expect(Stringable.of(subject).replaceStart(search, replace).toString()) + .toBe(expected); + + expect(Str.replaceStart(search, replace, subject)) + .toBe(expected); + + expect(replaceStart(search, replace, subject)) + .toBe(expected); + } +);