HiveBrain v1.2.0
Get Started
← Back to all entries
snippetjavascriptTip

Replace the last occurrence of a pattern in a JavaScript string

Submitted by: @import:30-seconds-of-code··
0
Viewed 0 times
lastjavascriptreplacetheoccurrencepatternstring

Problem

Replacing the first occurrence of a pattern in a string is easy, but what if you want to replace the last occurrence? This, admittedly, is a little trickier, especially if you want to match the functionality of String.prototype.replace().
First and foremost, we need to determine if the pattern is a string or a regular expression. If it's a string, we can use it as the match.
If it's a regular expression, we need to create a new regular expression using the RegExp() constructor and the RegExp.prototype.source of the pattern, adding the 'g' flag to it. Using String.prototype.match() and Array.prototype.slice(), we can then get the last match, if any.
We can then use String.prototype.lastIndexOf() to find the last occurrence of the match in the string. If a match is found, we can use String.prototype.slice() and a template literal to replace the matching substring with the given replacement. If no match is found, we can simply return the original string.
Putting everything together results in a versatile implementation that can handle both strings and regular expressions, and that matches the functionality of String.prototype.replace():

Solution

const replaceLast = (str, pattern, replacement) => {
  const match =
    typeof pattern === 'string'
      ? pattern
      : (str.match(new RegExp(pattern.source, 'g')) || []).slice(-1)[0];
  if (!match) return str;
  const last = str.lastIndexOf(match);
  return last !== -1
    ? `${str.slice(0, last)}${replacement}${str.slice(last + match.length)}`
    : str;
};

replaceLast('abcabdef', 'ab', 'gg'); // 'abcggdef'
replaceLast('abcabdef', /ab/, 'gg'); // 'abcggdef'
replaceLast('abcabdef', 'ad', 'gg'); // 'abcabdef'
replaceLast('abcabdef', /ad/, 'gg'); // 'abcabdef'


If it's a regular expression, we need to create a new regular expression using the RegExp() constructor and the RegExp.prototype.source of the pattern, adding the 'g' flag to it. Using String.prototype.match() and Array.prototype.slice(), we can then get the last match, if any.
We can then use String.prototype.lastIndexOf() to find the last occurrence of the match in the string. If a match is found, we can use String.prototype.slice() and a template literal to replace the matching substring with the given replacement. If no match is found, we can simply return the original string.
Putting everything together results in a versatile implementation that can handle both strings and regular expressions, and that matches the functionality of String.prototype.replace():

Code Snippets

const replaceLast = (str, pattern, replacement) => {
  const match =
    typeof pattern === 'string'
      ? pattern
      : (str.match(new RegExp(pattern.source, 'g')) || []).slice(-1)[0];
  if (!match) return str;
  const last = str.lastIndexOf(match);
  return last !== -1
    ? `${str.slice(0, last)}${replacement}${str.slice(last + match.length)}`
    : str;
};

replaceLast('abcabdef', 'ab', 'gg'); // 'abcggdef'
replaceLast('abcabdef', /ab/, 'gg'); // 'abcggdef'
replaceLast('abcabdef', 'ad', 'gg'); // 'abcabdef'
replaceLast('abcabdef', /ad/, 'gg'); // 'abcabdef'

Context

From 30-seconds-of-code: replace-last-occurrence

Revisions (0)

No revisions yet.