Replace text but keep case
Solution 1
Here’s a helper:
function matchCase(text, pattern) {
var result = '';
for(var i = 0; i < text.length; i++) {
var c = text.charAt(i);
var p = pattern.charCodeAt(i);
if(p >= 65 && p < 65 + 26) {
result += c.toUpperCase();
} else {
result += c.toLowerCase();
}
}
return result;
}
Then you can just:
"oooAsdFoooo".replace(r, function(match) {
return matchCase("qwer", match);
});
Solution 2
String.prototype.translateCaseSensitive = function (fromAlphabet, toAlphabet) {
var fromAlphabet = fromAlphabet.toLowerCase(),
toAlphabet = toAlphabet.toLowerCase(),
re = new RegExp("[" + fromAlphabet + "]", "gi");
return this.replace(re, function (char) {
var charLower = char.toLowerCase(),
idx = fromAlphabet.indexOf(charLower);
if (idx > -1) {
if (char === charLower) {
return toAlphabet[idx];
} else {
return toAlphabet[idx].toUpperCase();
}
} else {
return char;
}
});
};
and
"AbcD".translateCaseSensitive("abcdefg", "qwertyu")
will return:
"QweR"
Solution 3
I had a sentence where I had to replace each word with another word and that word can be longer/shorter than the word its replacing so its similar to the question but instead of a fixed length, they're dynamic.
My solution
For simplicity, I am focusing on a single word.
const oldWord = "tEsT";
const newWord = "testing";
Split both words so that I can iterate over each individual letters.
const oldWordLetters = oldWord.split("");
const newWordLetters = newWord.split("");
Now, I would iterate over the newWord
letters and use its index to then get the corresponding oldWord
letter in the same position. Then I would check if the old letter is capital and if it is then make the new letter in the same position capital as well.
for (const [i, letter] of newWordLetters.entries()) {
const oldLetter = oldWordLetters[i];
// stop iterating if oldWord is shorter (not enough letters to copy case).
if (!oldLetter) {
break;
}
const isCapital = oldLetter === oldLetter.toUpperCase();
// make the new letter in the same position as the old letter capital
if (isCapital) {
newWordLetters[i] = letter.toUpperCase();
}
}
The final world would be tEsTing
after joining the letters again.
const finalWord = newWordLetters.join("");
console.log(finalWord); // "tEsTing"
Full code
const oldWord = "tEsT";
const newWord = "testing";
const oldWordLetters = oldWord.split("");
const newWordLetters = newWord.split("");
for (const [i, letter] of newWordLetters.entries()) {
const oldLetter = oldWordLetters[i];
// stop iterating if oldWord is shorter (not enough letters to copy case).
if (!oldLetter) {
break;
}
const isCapital = oldLetter === oldLetter.toUpperCase();
// make the new letter in the same position as the old letter capital
if (isCapital) {
newWordLetters[i] = letter.toUpperCase();
}
}
const finalWord = newWordLetters.join("");
console.log(finalWord);
Solution 4
I'll leave this here for reference.
Scenario: case-insensitive search box on list of items, partial match on string should be displayed highlighted but keeping original case.
highlight() {
const re = new RegExp(this.searchValue, 'gi'); // global, insensitive
const newText = name.replace(re, `<b>$&</b>`);
return newText;
}
the $& is the matched text with case
Solution 5
You could create your own replace function such as
if(!String.prototype.myreplace){
String.prototype.myreplace = (function(obj){
return this.replace(/[a-z]{1,1}/gi,function(a,b){
var r = obj[a.toLowerCase()] || a;
return a.charCodeAt(0) > 96? r.toLowerCase() : r.toUpperCase();
});
});
}
This takes in a object that maps different letters. and it can be called such as follows
var obj = {a:'q',b:'t',c:'w'};
var s = 'AbCdea';
var n = s.myreplace(obj);
console.log(n);
This means you could potentially pass different objects in with different mappings if need be. Here's a simple fiddle showing an example (note the object is all lowercase but the function itself looks at case of the string as well)
Related videos on Youtube
ignacio.munizaga
Updated on June 27, 2022Comments
-
ignacio.munizaga almost 2 years
I have a set of strings that I need to replace, but I need to keep the case of letters.
Both the input words and output words are of the same length.
For example, if I need to replace "abcd" with "qwer", then the following should happen:
"AbcD" translates to "QweR" "abCd" translates to "qwEr"
and so on.
Right now I'm using JavaScript's
replace
, but capital letters are lost on translation.r = new RegExp( "(" + 'asdf' + ")" , 'gi' ); "oooAsdFoooo".replace(r, "qwer");
Any help would be appreciated.
-
Syknapse almost 5 yearsI found a much simpler and more elegant solution to what seems to be the same problem here: stackoverflow.com/questions/28841045/…
-
bertI would do it in 2 steps, first "oooAsdFoooo".search(r) which returns the index and then handle the case. But I would be excited if there is a way with a regex only
-
-
Tomalak almost 11 yearsThat's nice but only works for ASCII. :)
-
Ry- almost 11 years@Tomalak: If necessary, change
p >= 65 && p < 65 + 26
toUPPERCASE.test(p)
, changecharCodeAt
tocharAt
, and definevar UPPERCASE = /[whateverletters]/;
. -
jcsanyi almost 11 yearsThis replaces individual characters though - the original question is talking about replacing substrings. In your exmaple, the input string doesn't contain "abcdefg", so nothing should be replaced.
-
Tomalak almost 11 years@jcsanyi Hm. I didn't understand it that way. But it's probable that you're right.
-
Ry- almost 11 yearsOr maybe
toLocale{Upper,Lower}Case
. -
Alexander Dixon almost 3 yearsMay you please write this function in standard jQuery or vanilla JavaScript? EMCA 2015 is not compliant across the all the browsers we support.
-
Edie Lemoine over 2 yearsIt's not recommended to modify prototypes for maintainability. Create an exported function instead and require or import it. More details: flaviocopes.com/javascript-why-not-modify-object-prototype