Replace text but keep case

11,981

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)

Share:
11,981

Related videos on Youtube

ignacio.munizaga
Author by

ignacio.munizaga

Updated on June 27, 2022

Comments

  • ignacio.munizaga
    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
      Syknapse almost 5 years
      I found a much simpler and more elegant solution to what seems to be the same problem here: stackoverflow.com/questions/28841045/…
    • bert
      bert
      I 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
    Tomalak almost 11 years
    That's nice but only works for ASCII. :)
  • Ry-
    Ry- almost 11 years
    @Tomalak: If necessary, change p >= 65 && p < 65 + 26 to UPPERCASE.test(p), change charCodeAt to charAt, and define var UPPERCASE = /[whateverletters]/;.
  • jcsanyi
    jcsanyi almost 11 years
    This 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
    Tomalak almost 11 years
    @jcsanyi Hm. I didn't understand it that way. But it's probable that you're right.
  • Ry-
    Ry- almost 11 years
    Or maybe toLocale{Upper,Lower}Case.
  • Alexander Dixon
    Alexander Dixon almost 3 years
    May 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
    Edie Lemoine over 2 years
    It'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

Related