In fact, the regex you used (/a$/
) only replaces the a
in the end precisely because you used the bookmark $
, meaning "end of string". In addition, the for
is unnecessary as regex will already traverse the entire string looking for a
.
A solution with regex is to use /a([^a]*)$/
. The excerpt [^a]
means "all that nay for the letter a
" and the quantifier *
means "zero or more occurrences". And all this is in parentheses to form a catch group (Now we’ll understand why we created it).
That is, the regex /a([^a]*)$/
means:
- the letter
a
- followed by zero or more characters that are not the letter
a
- followed by the end of the string
In other words, the regex takes the last a
of the string, in addition to the characters that appear later, until the end of the string.
Characters that are not the letter a
were placed in parentheses to form a catch group, because it is possible to use its value in the replace
. So I don’t lose the information of what was after the a
. And as this is the first pair of parentheses that appears in the regex, may I refer to it using the special variable $1
:
let s = 'Uma string assim com várias letras a, mas só a última que é para substituir';
s = s.replace(/a([^a]*)$/, '@$1');
console.log(s);
// Uma string assim com várias letras a, mas só a última que é par@ substituir
Thus, the a
followed by "anything that is not a
" is replaced by @
followed by $1
(which are the same characters that existed after the a
). With this, only the last a
the string is exchanged, and the rest of the string remains the same.
Solution without regex
A solution without regex is also possible, using lastIndexOf
to obtain the index of the latter a
of the string, and then using substring
to get the parts of the string before and after the a
:
let s = 'Uma string assim com várias letras a, mas só a última que é para substituir';
let antiga = 'a';
let nova = '@';
var index = s.lastIndexOf(antiga);
// se encontrou a letra
if (index >= 0) {
s = s.substring(0, index) + nova + s.substring(index + antiga.length);
}
console.log(s);
// Uma string assim com várias letras a, mas só a última que é par@ substituir
The first substring
takes the entire chunk between the beginning of the string until the last occurrence of a
. The second substring
takes the whole stretch right after that a
, to the end of the string. And between the two I put the new string (in case, @
).
Regex versus substring
The solution with substring
works very well with strings of any size. Example:
let s = 'teste 123 outro teste fim';
let antiga = 'teste';
let nova = 'abcde';
var index = s.lastIndexOf(antiga);
// se encontrou a letra
if (index >= 0) {
s = s.substring(0, index) + nova + s.substring(index + antiga.length);
}
console.log(s);
// teste 123 outro abcde fim
If you are going to use regex, it is no use to use the above solution because the syntax [^...]
(character class denied) only works for single characters. To check if an entire text is the last occurrence, we can use a Negative Lookahead, which is basically a way for the regex to check if something doesn’t exist ahead:
let s = 'teste 123 outro teste fim';
let antiga = 'teste';
let nova = 'abcde';
s = s.replace(new RegExp(antiga + '(?!.*' + antiga + '.*$)(.*?)$'), nova + '$1');
console.log(s);
// teste 123 outro abcde fim
In this case, the created regex is equivalent to teste(?!.*teste.*$)(.*?)$
(that is, the string teste
, provided that there is no other occurrence of "test" until the end of the string). Then I keep capturing the rest of the string until the end, so I can have the variable $1
and use it on replace
.
thanks a lot guys, the regex worked, and also using the substring and the lastIndexOf also worked, opened up my mind a lot, it was worth too
– iago miranda
@iagomiranda If one of the answers solved your problem, you can choose the one that best solved and accept it, see here how and why to do it. It is not mandatory, but it is a good practice of the site, to indicate to future visitors that it solved the problem. Don’t forget that you can also vote in all the answers you found useful.
– hkotsubo