freeCodeCamp Challenge Guide: Search and Replace

Search and Replace


Problem Explanation

You will create a program that takes a sentence, then search for a word in it and replaces it for a new one while preserving the uppercase if there is one.

Relevant Links


Hints

Hint 1

  • Find the index where before is in the string.

Hint 2

  • Check first letter case.

Hint 3

  • Strings are immutable, you will need to save the edits on another variable, even if you must reuse the same one just to make it look like the changes where done using just that one variable.

Solutions

Solution 1 (Click to Show/Hide)
function myReplace(str, before, after) {
  // Find index where before is on string
  var index = str.indexOf(before);
  // Check to see if the first letter is uppercase or not
  if (str[index] === str[index].toUpperCase()) {
    // Change the after word to be capitalized before we use it.
    after = after.charAt(0).toUpperCase() + after.slice(1);
  }
  // Now replace the original str with the edited one.
  str = str.replace(before, after);

  return str;
}

// test here
myReplace("A quick brown fox jumped over the lazy dog", "jumped", "leaped");

Code Explanation

  • Use indexOf() to find location of before in string.
  • If first letter of before is capitalized, change first letter of after to uppercase.
  • Replace before in the string with after.
  • Return the new string.

Relevant Links

Solution 2 (Click to Show/Hide)
function myReplace(str, before, after) {
  // Check if first character of argument "before" is a capital or lowercase letter and change the first character of argument "after" to match the case
  if (/^[A-Z]/.test(before)) {
    after = after[0].toUpperCase() + after.substring(1)
  } else {
    after = after[0].toLowerCase() + after.substring(1)
  }

  // return string with argument "before" replaced by argument "after" (with correct case)
  return str.replace(before, after);
}

// test here
myReplace("A quick brown fox jumped over the lazy dog", "jumped", "leaped");

Code Explanation

  • In this solution, regular expression ^[A-Z] is used to check (test) if the first character of before is uppercase.
  • If first letter of before is capitalized, change the first letter of after to uppercase.
  • Else: If first letter of before is lowercase, change the first letter of after to lowercase
  • Return the new string replacing before with after.

Relevant Links

Solution 3 (Click to Show/Hide)
function myReplace(str, before, after) {
  // create a function that will change the casing of any number of letter in parameter "target"
  // matching parameter "source"
  function applyCasing(source, target) {
    // split the source and target strings to array of letters
    var targetArr = target.split("");
    var sourceArr = source.split("");
    // iterate through all the items of sourceArr and targetArr arrays till loop hits the end of shortest array
    for (var i = 0; i < Math.min(targetArr.length, sourceArr.length); i++) {
      // find out the casing of every letter from sourceArr using regular expression
      // if sourceArr[i] is upper case then convert targetArr[i] to upper case
      if (/[A-Z]/.test(sourceArr[i])) {
        targetArr[i] = targetArr[i].toUpperCase();
      }
      // if sourceArr[i] is not upper case then convert targetArr[i] to lower case
      else targetArr[i] = targetArr[i].toLowerCase();
    }
    // join modified targetArr to string and return
    return targetArr.join("");
  }

  // replace "before" with "after" with "before"-casing
  return str.replace(before, applyCasing(before, after));
}

// test here
myReplace("A quick brown fox jumped over the lazy dog", "jumped", "leaped");

Code Explanation

  • Both the before and after are passed as arguments to applyCasing().
  • The function applyCasing() is used to change the case of respective characters in targetArr i.e., after in accordance with that of characters in sourceArr i.e., before.
  • replace() is used to replace before with after, whose casing is same as before.
Solution 4 (Click to Show/Hide)
// Add new method to the String object, not overriding it if one exists already
String.prototype.capitalize =
  String.prototype.capitalize ||
  function() {
    return this[0].toUpperCase() + this.slice(1);
  };

const Util = (function() {
  // Create utility module to hold helper functions
  function textCase(str, tCase) {
    // Depending if the tCase argument is passed we either set the case of the
    // given string or we get it.
    // Those functions can be expanded for other text cases.

    if (tCase) {
      return setCase(str, tCase);
    } else {
      return getCase(str);
    }

    function setCase(str, tCase) {
      switch (tCase) {
        case "uppercase":
          return str.toUpperCase();
        case "lowercase":
          return str.toLowerCase();
        case "capitalized":
          return str.capitalize();
        default:
          return str;
      }
    }

    function getCase(str) {
      if (str === str.toUpperCase()) {
        return "uppercase";
      }
      if (str === str.toLowerCase()) {
        return "lowercase";
      }
      if (str === str.capitalize()) {
        return "capitalized";
      }
      return "normal";
    }
  }

  return {
    textCase
  };
})();

function myReplace(str, before, after) {
  const { textCase } = Util;
  const regex = new RegExp(before, "gi");
  const replacingStr = textCase(after, textCase(before));

  return str.replace(regex, replacingStr);
}
Solution 5 (Click to Show/Hide)
function myReplace(str, before, after) {
  const myArr = str.split(" ");
  const [wordToReplace] = myArr.filter(item => item === before);
  return wordToReplace[0].toUpperCase() !== wordToReplace[0]
    ? myArr.map(item => (item === before ? after : item)).join(" ")
    : myArr
        .map(item =>
          item === before ? after[0].toUpperCase() + after.slice(1) : item
        )
        .join(" ");
}

// test:
myReplace("A quick brown fox jumped over the lazy dog", "jumped", "leaped");

Relevant Links

14 Likes

Here’s a simple, straightforward solution:
(And thank you, @Rafase282, for all of your hints and help.)

function myReplace(str, before, after) {
  if (before[0] === before[0].toUpperCase()) {
    after = after.replace(after[0], after[0].toUpperCase());
  }
  return str.replace(before, after);
}

For Array Lovers here is something short and precise =>


function myReplace(str, before, after) {
  return str
         .split(" ")
         .map((x) => (x == before)? 
              (x[0] == x[0].toUpperCase()) ?
              (after[0].toUpperCase() + after.slice(1)) : after.toLowerCase() 
              : x)
         .join(" ");

}

This also takes care if after starts with an upper case character and before is a lowercase string

23 Likes

Here’s a simple, straightforward solution (white space between lines for clarity):

function myReplace(str, before, after) {
   
  \\ IF statement checks to see if the first letter of before (before[0]) is equal to upper case      
  if (before[0] === before[0].toUpperCase()) {
   
    \\ if before[0] IS upper case, then sets after equal to after with the first letter replaced with upper case        
    after = after.replace(after[0], after[0].toUpperCase());
  }
  return str.replace(before, after);
}

myReplace("His name is Tom", "Tom", "john");   //  returns "His name is John"

Thanks, @Rafase282, for all of your posts with helpful hints!

2 Likes

SPOILER ALERT!!!

I solved it like this:-

function myReplace(str, before, after) {

if (before[0] === before[0].toUpperCase()) {
    after = after[0].toUpperCase() + after.slice(1);
}
str = str.replace(before, after);
return str;

}

myReplace(“A quick brown fox jumped over the lazy dog”, “jumped”, “leaped”);

Based on the things we have learned it seemed the easiest solution. Granted it only works on the premise that only the first letter of the word will be capitalised, but it passes all the tests set.

6 Likes

Here’s my solution:

function myReplace(str, before, after) {
  if (str.charCodeAt(str.indexOf(before)) >= 65 && str.charCodeAt(str.indexOf(before)) <= 90) {
     return str.replace(before, after.charAt(0).toUpperCase() + after.slice(1));
  }
  return str.replace(before, after);
}

myReplace("Let us get back to more Coding", "Coding", "algorithms");

Am I the only one who solved this by checking the unicode values? Probably not as eloquent as the solutions above but it works!

Here is my solution with comments to clarify.
`function myReplace(str, before, after) {
if (before[0] === before[0].toUpperCase()){ //checks if the first character of before is capital
after = after.charAt(0).toUpperCase() + after.slice(1); //if the first character of before is capital then the first character of after is made into a capital
}
var newStr = str.replace(before, after); //create a new string where the before word is replaced with the after word
return newStr; //return that new string
}

myReplace(“A quick brown fox Jumped over the lazy dog”, “Jumped”, “leaped”);`

My quick solution:

function myReplace(str, before, after) {
return str.split(before).join(before[0] == before[0].toUpperCase() ? after.charAt(0).toUpperCase() + after.slice(1): after);
}

myReplace(“He is Sleeping on the couch”, “Sleeping”, “sitting”);

3 Likes

I used array functions, to come up with this solution that is case-sensitive beyond the first character.

function myReplace (str, before, after) {

      var boolArr =  before.split("").map(function (bLet) {
        return bLet===bLet.toUpperCase() ? true : false;
      });    
  
      after = after.split("").map(function (aLet) {
        return boolArr[after.indexOf(aLet)] ? aLet.toUpperCase() : aLet.toLowerCase();          
      }).join("");
  
     return str.replace(before,after);
  }
  1. List item
1 Like

Great solution. Very efficient!

My solution -

function myReplace(str, before, after) {
  
  if (/[A-Z]/.test(before[0])) {
    after = after.replace(after[0],after[0].toUpperCase());
  } 
  return str.replace(before,after);
}
3 Likes

function myReplace(str, before, after) {

after = after.split(’’);
if(before.charCodeAt(0)>=65 && before.charCodeAt(0)<=90){
var upCase = after[0].toUpperCase();
after.splice(0,1,upCase);

}

return str.replace(before,after.join(’’));

}

I like this one, more efficient than mine (which is below); one note however, yours could return an unexpected uppercase in ‘after’ if ‘before’ has a number in it. Easily remedied though.

Here’s mine:


function myReplace(str, before, after) {
  var after1 = "";
  for(var i = 0; i < Math.min(before.length, after.length); i++) {
    if(isNaN(before.charAt(i)) && before.charAt(i) === before.charAt(i).toUpperCase()) {
      after1 += after.charAt(i).toUpperCase();
    }
    else if(isNaN(before.charAt(i)) && before.charAt(i) === before.charAt(i).toLowerCase()) {
      after1 += after.charAt(i).toLowerCase();
    }
    else {
      after1 += after.charAt(i);
    }
  }
  if(after1.length < after.length) {
    after1 += after.slice(after1.length - after.length);
  }
  return str.replace(before, after1);
}

My solution:

function myReplace(str, before, after) {
   return str.replace(before, () => before[0] == before[0].toUpperCase() ? 
      after.replace(after[0], after[0].toUpperCase()) : after);
}
1 Like
function myReplace(str, before, after) {
  //if (before.charCodeAt(0) < 90) {
  if (/[A-Z]/.test(before[0])) {
    after = after.split('');    
    after.splice(0, 1, after[0].toUpperCase());
    after = after.join('');
  }
  return str.replace(new RegExp(before, 'g'), after);
}

myReplace("He is Sleeping on the couch", "Sleeping", "sitting");

My solution:

function myReplace(str, before, after) {
  
  var toReplace = str.substr(str.indexOf(before), before.length).split("");
  
  if (toReplace[0].toUpperCase() == toReplace[0]) {
    after = after.split("")[0].toUpperCase() + after.substr(1);
  }
  
  return str.replace(before, after);
}
//test
myReplace("A quick brown fox jumped over the lazy dog", "jumped", "leaped");

All of these solutions are all well and good and pass the tests, but what if you need to replace more than one instance of a word in str and maintain case? All of these solutions fail in that case. See https://github.com/freeCodeCamp/freeCodeCamp/issues/15260

1 Like

This is the best I could come up with that matches the specific case of before and replaces all instances:

function myReplace(str, before, after) {

  if (/^[A-Z]/.test(before)){
    after = after.charAt(0).toUpperCase() + after.slice(1);
  }

  return str.replace(new RegExp(before, 'g'),after);

}
1 Like

My solutions:

function myReplace(str, before, after) {

return str.replace(before, function () {
    return before.charCodeAt(0)<=90 ? after.charAt(0).toUpperCase()+after.slice(1) : after.charAt(0).toLowerCase()+after.slice(1);
});

}

and other

function myReplace(str, before, after) {

return str.replace(before, function () {
 var arrAfter=after.split('');
 before.charCodeAt(0)<=90 ? arrAfter.splice(0, 1, after[0].toUpperCase()) : arrAfter.splice(0, 1, after[0].toLowerCase());
  return arrAfter.join(''); 
});

}