JavaScript: replace last occurrence of text in a string

JavascriptStringReplace

Javascript Problem Overview


See my code snippet below:

var list = ['one', 'two', 'three', 'four'];
var str = 'one two, one three, one four, one';
for ( var i = 0; i < list.length; i++)
{
     if (str.endsWith(list[i])
     {
         str = str.replace(list[i], 'finish')
     }
 }

I want to replace the last occurrence of the word one with the word finish in the string, what I have will not work because the replace method will only replace the first occurrence of it. Does anyone know how I can amend that snippet so that it only replaces the last instance of 'one'

Javascript Solutions


Solution 1 - Javascript

Well, if the string really ends with the pattern, you could do this:

str = str.replace(new RegExp(list[i] + '$'), 'finish');

Solution 2 - Javascript

You can use String#lastIndexOf to find the last occurrence of the word, and then String#substring and concatenation to build the replacement string.

n = str.lastIndexOf(list[i]);
if (n >= 0 && n + list[i].length >= str.length) {
    str = str.substring(0, n) + "finish";
}

...or along those lines.

Solution 3 - Javascript

I know this is silly, but I'm feeling creative this morning:

'one two, one three, one four, one'
.split(' ') // array: ["one", "two,", "one", "three,", "one", "four,", "one"]
.reverse() // array: ["one", "four,", "one", "three,", "one", "two,", "one"]
.join(' ') // string: "one four, one three, one two, one"
.replace(/one/, 'finish') // string: "finish four, one three, one two, one"
.split(' ') // array: ["finish", "four,", "one", "three,", "one", "two,", "one"]
.reverse() // array: ["one", "two,", "one", "three,", "one", "four,", "finish"]
.join(' '); // final string: "one two, one three, one four, finish"

So really, all you'd need to do is add this function to the String prototype:

String.prototype.replaceLast = function (what, replacement) {
	return this.split(' ').reverse().join(' ').replace(new RegExp(what), replacement).split(' ').reverse().join(' ');
};

Then run it like so: str = str.replaceLast('one', 'finish');

One limitation you should know is that, since the function is splitting by space, you probably can't find/replace anything with a space.

Actually, now that I think of it, you could get around the 'space' problem by splitting with an empty token.

String.prototype.reverse = function () {
	return this.split('').reverse().join('');
};

String.prototype.replaceLast = function (what, replacement) {
	return this.reverse().replace(new RegExp(what.reverse()), replacement.reverse()).reverse();
};

str = str.replaceLast('one', 'finish');

Solution 4 - Javascript

Not as elegant as the regex answers above, but easier to follow for the not-as-savvy among us:

function removeLastInstance(badtext, str) {
    var charpos = str.lastIndexOf(badtext);
    if (charpos<0) return str;
    ptone = str.substring(0,charpos);
    pttwo = str.substring(charpos+(badtext.length));
    return (ptone+pttwo);
}

I realize this is likely slower and more wasteful than the regex examples, but I think it might be helpful as an illustration of how string manipulations can be done. (It can also be condensed a bit, but again, I wanted each step to be clear.)

Solution 5 - Javascript

Here's a method that only uses splitting and joining. It's a little more readable so thought it was worth sharing:

    String.prototype.replaceLast = function (what, replacement) {
		var pcs = this.split(what);
		var lastPc = pcs.pop();
		return pcs.join(what) + replacement + lastPc;
	};

Solution 6 - Javascript

Thought I'd answer here since this came up first in my Google search and there's no answer (outside of Matt's creative answer :)) that generically replaces the last occurrence of a string of characters when the text to replace might not be at the end of the string.

if (!String.prototype.replaceLast) {
    String.prototype.replaceLast = function(find, replace) {
        var index = this.lastIndexOf(find);

        if (index >= 0) {
            return this.substring(0, index) + replace + this.substring(index + find.length);
        }
    
        return this.toString();
    };
}

var str = 'one two, one three, one four, one';

// outputs: one two, one three, one four, finish
console.log(str.replaceLast('one', 'finish'));

// outputs: one two, one three, one four; one
console.log(str.replaceLast(',', ';'));

Solution 7 - Javascript

A simple answer without any regex would be:

str = str.substr(0, str.lastIndexOf(list[i])) + 'finish'

Solution 8 - Javascript

I did not like any of the answers above and came up with the below

function isString(variable) { 
    return typeof (variable) === 'string'; 
}

function replaceLastOccurrenceInString(input, find, replaceWith) {
    if (!isString(input) || !isString(find) || !isString(replaceWith)) {
        // returns input on invalid arguments
        return input;
    }

    const lastIndex = input.lastIndexOf(find);
    if (lastIndex < 0) {
        return input;
    }

    return input.substr(0, lastIndex) + replaceWith + input.substr(lastIndex + find.length);
}

Usage:

const input = 'ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty';
const find = 'teen';
const replaceWith = 'teenhundred';

const output = replaceLastOccurrenceInString(input, find, replaceWith);
console.log(output);

// output: ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteenhundred twenty

Hope that helps!

Solution 9 - Javascript

If speed is important, use this:

/**
 * Replace last occurrence of a string with another string
 * x - the initial string
 * y - string to replace
 * z - string that will replace
 */
function replaceLast(x, y, z){
    var a = x.split("");
    var length = y.length;
    if(x.lastIndexOf(y) != -1) {
        for(var i = x.lastIndexOf(y); i < x.lastIndexOf(y) + length; i++) {
            if(i == x.lastIndexOf(y)) {
                a[i] = z;
            }
            else {
                delete a[i];
            }
        }
    }

    return a.join("");
}

It's faster than using RegExp.

Solution 10 - Javascript

Simple solution would be to use substring method. Since string is ending with list element, we can use string.length and calculate end index for substring without using lastIndexOf method

str = str.substring(0, str.length - list[i].length) + "finish"

Solution 11 - Javascript

Couldn't you just reverse the string and replace only the first occurrence of the reversed search pattern? I'm thinking . . .

var list = ['one', 'two', 'three', 'four'];
var str = 'one two, one three, one four, one';
for ( var i = 0; i < list.length; i++)
{
     if (str.endsWith(list[i])
     {
         var reversedHaystack = str.split('').reverse().join('');
         var reversedNeedle = list[i].split('').reverse().join('');

         reversedHaystack = reversedHaystack.replace(reversedNeedle, 'hsinif');
         str = reversedHaystack.split('').reverse().join('');
     }
 }

Solution 12 - Javascript

Old fashioned and big code but efficient as possible:

function replaceLast(origin,text){
	textLenght = text.length;
	originLen = origin.length
	if(textLenght == 0)
		return origin;

	start = originLen-textLenght;
	if(start < 0){
		return origin;
	}
	if(start == 0){
		return "";
	}
	for(i = start; i >= 0; i--){
		k = 0;
		while(origin[i+k] == text[k]){
			k++
			if(k == textLenght)
				break;
		}
		if(k == textLenght)
			break;
	}
	//not founded
	if(k != textLenght)
		return origin;

	//founded and i starts on correct and i+k is the first char after
	end = origin.substring(i+k,originLen);
	if(i == 0)
		return end;
	else{
		start = origin.substring(0,i) 
		return (start + end);
	}
}

Solution 13 - Javascript

I would suggest using the replace-last npm package.

var str = 'one two, one three, one four, one';
var result = replaceLast(str, 'one', 'finish');
console.log(result);

<script src="https://unpkg.com/replace-last@latest/replaceLast.js"></script>

This works for string and regex replacements.

Solution 14 - Javascript

this way works for me. take a look at replace last character in string javascript

str.replace(/one([^one]*$)/, 'finish$1')

Solution 15 - Javascript

function replaceLast(text, searchValue, replaceValue) {
  const lastOccurrenceIndex = text.lastIndexOf(searchValue)
  return `${
      text.slice(0, lastOccurrenceIndex)
    }${
      replaceValue
    }${
      text.slice(lastOccurrenceIndex + searchValue.length)
    }`
}

Solution 16 - Javascript

str = (str + '?').replace(list[i] + '?', 'finish');

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRuthView Question on Stackoverflow
Solution 1 - JavascriptPointyView Answer on Stackoverflow
Solution 2 - JavascriptT.J. CrowderView Answer on Stackoverflow
Solution 3 - JavascriptMattView Answer on Stackoverflow
Solution 4 - JavascriptWilsonCPUView Answer on Stackoverflow
Solution 5 - Javascriptmr.freezeView Answer on Stackoverflow
Solution 6 - JavascriptIrvingView Answer on Stackoverflow
Solution 7 - JavascriptTim LongView Answer on Stackoverflow
Solution 8 - JavascriptPepijn OlivierView Answer on Stackoverflow
Solution 9 - JavascriptPascutView Answer on Stackoverflow
Solution 10 - JavascriptHexer338View Answer on Stackoverflow
Solution 11 - JavascriptFustyView Answer on Stackoverflow
Solution 12 - Javascriptdario nascimentoView Answer on Stackoverflow
Solution 13 - Javascriptdanday74View Answer on Stackoverflow
Solution 14 - JavascriptYoel DuranView Answer on Stackoverflow
Solution 15 - JavascriptMuhamet RexhepiView Answer on Stackoverflow
Solution 16 - JavascriptzaxvoxView Answer on Stackoverflow