Don't understand why replace() method is not working as expected - javascript

Working on the following problem:
Create a function called alienLanguage where the input will be a str and the output should capitalize all letters except for the last letter of each word
alienLanguage("My name is John") should return "My NAMe Is JOHn"
This is what I have coded:
function alienLanguage(str){
var words = str.toUpperCase().split(' ').map(function (a) {
return a.replace(a[a.length - 1], a[a.length - 1].toLowerCase())
});
return words.join(' ');
}
All of the example test cases work except for the following:
Expected: '\'THIs Is An EXAMPLe\'', instead got: '\'THIs Is An eXAMPLE\''
Why is the e in eXAMPLE turning lowercase? Shouldn't everything automatically turn upperCase ?
edit: I just realized that there are 2 e's and the first one is being replaced. How can I replace the last e? and isn't the last character specified already?

isn't the last character specified already?
No, you've only specified what character to replace, not where. replace searches the string for the expression.
How can I replace the last e?
Don't use replace at all. It does construct a new string anyway, and you can do that much easier:
function alienLanguage(str) {
return str.split(' ').map(function(a) {
return a.slice(0, -1).toUpperCase() + a.slice(-1).toLowerCase();
}).join(' ');
}
You also could use replace, but would use it with regular expression:
function alienLanguage(str) {
return str.toUpperCase().replace(/.\b/g, function(last) {
// ^^^^^^ matches all characters before a word boundary
return last.toLowerCase();
});
}

You don't need to split the string into words. Just use a positive lookahead assertion in your regex to upper-case all letters that are immediately followed by another letter, like this:
function alienLanguage(str){
return str.replace(/(\w)(?=\w)/g, l => l.toUpperCase())
}

You can use substring. Your replace replaces and replaces the first occurrence of the last character in the words -- definitely what you're after:
function alienLanguage(str){
var words = str.toUpperCase().split(' ').map(function (a) {
return a.length ? a.substring(0, a.length - 2) + a[a.length - 1].toLowerCase() : a;
});
return words.join(' ');
}

As #TatsuyukiIshi said, you need to change the use of replace() for regular assignment. For extra help, here is an updated version of your alienLanguage function:
function alienLanguage(str){
return str.toUpperCase().split(' ').map(function(word) {
return word.slice(0, -1) + word.substr(-1).toLowerCase()
}).join(' ')
}
Fiddle here
Extra notes:
word.slice(0,-1) returns the word minus the last character.
word.substr(-1) returns the last character as a string.
.map() returns an array, so you can call join() directly on the result.

replace() is searching using a pattern (or regular expression) and it replaces all occurrences.
Instead, you want to truncate and create a new string, which is known as assignment in other languages (but strings in JS are immutable). See here for more details.

Try it.
function alienLanguage(str){
var words = str.toUpperCase().split(' ').map(function (a) {
return a.substr(0, a.length - 1) +a[a.length - 1].toLowerCase() + a.substr(a.length - 1 + 1);
});
return words.join(' ');
}

Instead of searching for the letter, just concatenate the uppercase part of the string up to the last letter with the lowercased last letter.
This should do the trick:
function alienLanguage(str) {
return str.split(' ').map(function(a) {
return a.slice(0, -1).toUpperCase() + a.slice(-1).toLowerCase();
}).join(' ');
}

Related

Array manipulation error with regex - Kata 6 Codewar

In theory it should transform a given array to camel case. I don't understand what is wrong
function toCamelCase(str){
if(str.length === 0) return ""
let array = str.split(/([_-])/);
array.forEach(word =>{
word == "-" ? word.replace("") : word.charAt(0).toUpperCase()
})
return array
}
The .replace() method doesn't modify the word variable, it instead returns a new modified string. So your code is producing new values within the loop but doesn't do anything with those values. Moreover, word here is a value and not a reference to your array values, so you can't modify them directly from within your forEach() loop and expect it to modify the string values from your array. You instead need to create a new array, with each element transformed, which can be done by using .map() and returning the new value:
function toCamelCase(str) {
const array = str.split(/[_-]/);
return array.map((word, i) => {
return i === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1)
}).join("");
}
console.log(toCamelCase("this-is-some-text"));
Note that you can remove the capturing group from your .split() to remove the _ and - chars from your array so that you don't need to remove them when you map.
Note that for something like this, if you're already using regular expressions in your .split(), you might consider using .replace() with a replacement function, for example, something like:
function toCamelCase(str) {
return str.replace(/-\w/g, ([,m]) => m.toUpperCase());
}
console.log(toCamelCase("this-is-some-text"));
word == "-" ? word.replace("") : word.charAt(0).toUpperCase() is just a ternary statement floating in space. This code isn't altering any variables. It's equivalent to:
if(word == "-"){
word.replace("")
}
else{
word.charAt(0).toUpperCase()
}
Really, you don't need to mess with arrays if you make use of .replace()'s callback function.
function toCamelCase(str) {
// Match underscore or dash followed by a letter, case-insensitively
// Store the letter in a capture group; $1 in this case
return str.replace( /[_-]([a-z])/gi, function( matches ) {
// Uppercase the letter
return matches[ 1 ].toUpperCase()
} );
}
console.log( toCamelCase( 'to-be_Camel_cased' ) );

JavaScript: Amend the Sentence

I am having trouble below javaScript problem.
Question:
You have been given a string s, which is supposed to be a sentence. However, someone forgot to put spaces between the different words, and for some reason they capitalized the first letter of every word. Return the sentence after making the following amendments:
Put a single space between the words.
Convert the uppercase letters to lowercase.
Example
"CodefightsIsAwesome", the output should be "codefights is awesome";
"Hello", the output should be "hello".
My current code is:
Right now, my second for-loop just manually slices the parts from the string.
How can I make this dynamic and insert "space" in front of the Capital String?
You can use String.prototype.match() with RegExp /[A-Z][^A-Z]*/g to match A-Z followed by one or more characters which are not A-Z, or character at end of string; chain Array.prototype.map() to call .toLowerCase() on matched words, .join() with parameter " " to include space character between matches at resulting string.
var str = "CodefightsIsAwesome";
var res = str.match(/[A-Z][^A-Z]*/g).map(word => word.toLowerCase()).join(" ");
console.log(res);
Alternatively, as suggested by #FissureKing, you can use String.prototype.repalce() with .trim() and .toLowerCase() chained
var str = "CodefightsIsAwesome";
var res = str.replace(/[A-Z][^A-Z]*/g, word => word + ' ').trim().toLowerCase();
console.log(res);
Rather than coding a loop, I'd do it in one line with a (reasonably) simple string replacement:
function amendTheSentence(s) {
return s.replace(/[A-Z]/g, function(m) { return " " + m.toLowerCase() })
.replace(/^ /, "");
}
console.log(amendTheSentence("CodefightsIsAwesome"));
console.log(amendTheSentence("noCapitalOnFirstWord"));
console.log(amendTheSentence("ThereIsNobodyCrazierThanI"));
That is, match any uppercase letter with the regular expression /[A-Z]/, replace the matched letter with a space plus that letter in lowercase, then remove any space that was added at the start of the string.
Further reading:
String .replace() method
Regular expressions
We can loop through once.
The below assumes the very first character should always be capitalized in our return array. If that is not true, simply remove the first if block from below.
For each character after that, we check to see if it is capitalized. If so, we add it to our return array, prefaced with a space. If not, we add it as-is into our array.
Finally, we join the array back into a string and return it.
const sentence = "CodefightsIsAwesome";
const amend = function(s) {
ret = [];
for (let i = 0; i < s.length; i++) {
const char = s[i];
if (i === 0) {
ret.push(char.toUpperCase());
} else if (char.toUpperCase() === char) {
ret.push(` ${char.toLowerCase()}`);
} else {
ret.push(char);
}
}
return ret.join('');
};
console.log(amend(sentence));

Javascript wrong outcome when crafting a custom regex camelCase solution for strings

I'm attempting a Javascript challenge who's instructions are:
Complete the method/function so that it converts dash/underscore delimited
words into camel casing. The first word within the output should be
capitalized only if the original word was capitalized.
Examples:
toCamelCase("the-stealth-warrior")
// returns "theStealthWarrior"
toCamelCase("The_Stealth_Warrior")
// returns "TheStealthWarrior"
My solution is:
function toCamelCase(str) {
console.log(str);
var camel = str.replace(/(?:^\w|[A-Z]|-\w|_\w)/g, function(letter, index) {
return index === 0 && letter === letter.toLowercase ?
letter.toLowercase : letter.toUpperCase();
}).replace(/(-|_)/g, "");
console.log(camel);
return camel;
}
and the output when using my code with the test cases is:
toCamelCase('the_stealth_warrior') did not return correct value -
Expected: theStealthWarrior, instead got: TheStealthWarrior
any ideas where this is going wrong? I feel my conditions in the ternary operator should be returning a lowercase t.
This bit of code here is causing your problem:
function(letter, index) {
return index === 0 && letter === letter.toLowercase ?
letter.toLowercase : letter.toUpperCase();
}
You probably meant to use toLowerCase(), but instead you've provided a reference to a non-existent property of letter. Since toLowercase doesn't exist, it will return undefined which will cause your conditional to always return false.
Change the line to:
function(letter, index) {
return index === 0 && letter === letter.toLowerCase() ?
letter.toLowerCase() : letter.toUpperCase();
}
How about simplifying it a bit to this:
function toCamelCase(str) {
return str.replace(/[-_](.?)/g, function(match, p1) {
return p1.toUpperCase();
})
}
document.write(toCamelCase("the-stealth-warrior") + "<br>");
document.write(toCamelCase("The_Stealth_Warrior") + "<br>");
Explanation:
[-_] Find either a - or _
(.?) Followed by any other character and put this other character in a group.
Then call .replace() on that with a custom callback using the g flag to do all matches.
The custom callback will be passed the full match as the first argument and any groups in the match as the subsequent arguments. Since what we want to convert this to is just the uppercase version of the first group, we just uppercase the second argument with return p1.toUpperCase() and then the whole match is replaced by an upper case version of the first matched group. This then converts _x to X.
This skips the leading character because there's no - or _ before it.
This skips any trailing - or _ because there's no character after it.

Regex for alternating indexes from a word boundary

I've just finished this programming challenge on CodeWars:
Write a function toWeirdCase that accepts a string, and returns the same string with all even indexed characters in each word upper cased, and all odd indexed characters in each word lower cased. The indexing just explained is zero based, so the zero-ith index is even, therefore that character should be upper cased.
I tried to figure this out with regex before giving up and simply using a for loop with indexes. Just to confirm, the index of capitalising letters resets to 0 whenever there is a space. So ThIs Is A CoRrEcT AnSwEr but ThIs iS nOt, because every first letter of each word must be capitalised.
With that in mind, is there an approach to look for alternate (odd or even) indexes using regex? In this case, find a word boundary using \b, and then every even index from there, until the end of the word?
You can borrow map to convert apply a function to each character, i%2 to detect if i is odd, and toLowerCase or toUpperCase to change the case:
function toWeirdCase(str) {
return [].map.call(str, function(char, i) {
return char[i%2 ? 'toLowerCase' : 'toUpperCase']();
}).join('');
}
There are multiple ways to reset the index at each space. For example,
function toWeirdCase(str) {
var i = 0;
return [].map.call(str, function(char) {
if(char === ' ') i = -1;
return char[i++ % 2 ? 'toLowerCase' : 'toUpperCase']();
}).join('');
}
The function parameter to replace receives the match offset after the matched string and matched groups.
function toWeirdCase(s) {
return s.replace(/[a-zA-Z]/g, function (ltr, offset) {
return offset & 1 ? ltr.toLowerCase() : ltr.toUpperCase();
});
}
You need to split the input into words, then weird case each word:
function toWeirdCase(str) {
return str.split(' ').map(weirdCaseWord).join(' ');
}
weirdCaseWord can be written as in the other answer:
function weirdCaseWord(str) {
return str.split('').map(function(char, i) {
return char[i%2 ? 'toLowerCase' : 'toUpperCase']();
}).join('');
}
If you prefer, you could use a single map with a flag which is toggled on each character, and reset on a space:
function toWeirdCase(str) {
var even = false;
return str.split('').map(function(char) {
even = char === ' ' ? false : !even;
return char[even ? 'toUpperCase' : 'toLowerCase']();
}).join('');
}

Javascript to capitalize the next char after " Mc"

Given a string like Marty Mcfly is there a regex or other one line solution to capitalize the 'f' so I get Marty McFly?
I can always count on the space between first and last and the first letter of the last name (i.e. the M) will always be caps.
I'm pretty open to just about any javascript, jquery, regex solution, I just need it to be short and sweet.
I've got a method that takes the string apart using indexOf and substring but I'm hoping theres a regex or something similar.
You can take advantage of the form of String.replace which takes a function as its second argument:
function fixMarty(s) {
return (""+s).replace(/Mc(.)/g, function(m, m1) {
return 'Mc' + m1.toUpperCase();
});
}
fixMarty('Marty Mcfly'); // => "Marty McFly"
fixMarty("Mcdonald's"); // => "McDonald's"
This is a perfect case for using a callback with .replace().
function fixMc(str) {
return(str.replace(/\bMc(\w)/, function(match, p1) {
return(match.slice(0, -1) + p1.toUpperCase());
}));
}
Here's a jsFiddle http://jsfiddle.net/jfriend00/Qbf8R/ where you can see it in action on a several different test cases.
By way of explanation for the how the callback works, the parameter match is the whole regex match, the parameter p1 is what the first parenthesized group matched and the callback returns what you want to replace the whole regex match with.
var text = 'Marty Mcfly';
text = text.replace(/Mc[a-z]/, function (k)
{
return 'Mc' + k[2].toUpperCase();
}
);
Use a combination of RegEx's exec method and String's replace method:
var name = 'Marty Mcfly',
pattern = /\bmc([a-z])/gi,
match = pattern.exec(name);
if (match) {
alert(name.replace(pattern, 'Mc' + match[1].toUpperCase()));
}
Here's a version that works with "Mac":
var name = 'Connor Macleod',
pattern = /\b(mc|mac)([a-z])/gi,
match = pattern.exec(name);
if (match) {
alert(name.replace(pattern, match[1] + match[2].toUpperCase()));
}
Here's the best I can do:
'Marty Mcfly'.replace(/ mc([a-z])/i, function (str, $1) {return " Mc" + $1.toUpperCase()})

Categories

Resources