Why does toLowerCase() does not work with replace()? - javascript

Given Below is a simple function to capitalize the first words in a sentence
Eg: INPUT: 'JavaSCRipt is The BEST'
OUTPUT: 'JavaScript Is The Best'
const firstupper = function(str){
const arr = str.split(' ');
const newArr = [];
for(let item of arr){
item = item.toLowerCase();
newArr.push(item.replace(item[0], item[0].toUpperCase()));
}
const newstr = newArr.join(' ');
console.log(newstr);
}
firstupper('javaSCript is THE besT');
P.S -- This code works fine
Why can't I make to lower case and then replace the first letter in upper case in single line
like : newArr.push(item.toLowerCase().replace(item[0], item[0].toUpperCase()));
When I write the code using this it is changing the first word to lower if it is in upper case vice versa
Eg: INPUT -> 'JAvaScript is The best'
OUTPUT - > 'javascript Is the Best'

Because that changes the logic. In this version, all reads of item in the .push() operation are lower-cased:
item = item.toLowerCase();
newArr.push(item.replace(item[0], item[0].toUpperCase()));
But in this version, only the first use of item is lower-cased:
newArr.push(item.toLowerCase().replace(item[0], item[0].toUpperCase()));
The references to item[0] both still use whatever the original casing was. To make it the same logic you'd need to repeat the case change there as well:
newArr.push(item.toLowerCase().replace(item.toLowerCase()[0], item.toLowerCase()[0].toUpperCase()));
Which clearly is too cluttered and unnecessarily repeats the operation. So the original working version is preferred.

This could help
const str = 'JavaSCRipt is The BEST';
//split the above string into an array of strings
//whenever a blank space is encountered
const arr = str.split(" ");
//loop through each element of the array and capitalize the first letter.
for (var i = 0; i < arr.length; i++) {
arr[i] = arr[i].toLowerCase();
arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].slice(1);
}
//Join all the elements of the array back into a string
//using a blankspace as a separator
const str2 = arr.join(" ");
console.log(str2);
//Outptut: Javascript Is The Best

Related

How to add commas in between words in string in Javascript

I'm trying to add commas in between the first and last names in parentheses.
//Input:
s = "Fred:Corwill;Wilfred:Corwill;Barney:Tornbull;Betty:Tornbull;Bjon:Tornbull;Raphael:Corwill;Alfred:Corwill";
//Expected output: "(CORWILL, ALFRED)(CORWILL, FRED)(CORWILL, RAPHAEL)(CORWILL, WILFRED)(TORNBULL, BARNEY)(TORNBULL, BETTY)(TORNBULL, BJON)"
What my code is currently outputting:
(CORWILL ALFRED) (CORWILL FRED) (CORWILL RAPHAEL) (CORWILL WILFRED) (TORNBULL BARNEY) (TORNBULL BETTY) (TORNBULL BJON)
I've tried a number of approaches like changing how the characters are replaced in the beginning when I reassign s (the string) so that I am not removing the commas in the first place, to then have to replace them...but when I did that, the regex I have was no longer working, and I am not sure why that is. So I tried to find another regex to use so I could work around that problem, but that has equally been a pain, so I decided to just stick to solving it this way: trying to find a way to find commas in between the first, and last names in the parentheses.
Full problem & code:
/*Could you make a program that
• makes this string uppercase
• gives it sorted in alphabetical order by last name.
When the last names are the same, sort them by first name. Last name and first name of a guest come in the result between parentheses separated by a comma.
*/
function meeting(s) {
s = s.replace(/:/g, ", ").toUpperCase();
//order alphabetically based on Last, then first name
const semicolon = ';'
let testArr = s.split(semicolon)
testArr.sort(function compare(a, b) {
var splitA = a.split(",");
var splitB = b.split(",");
var firstA = splitA[0]
var firstB = splitB[0]
var lastA = splitA[splitA.length - 1];
var lastB = splitB[splitB.length - 1];
if (lastA < lastB) return -1;
if (lastA > lastB) return 1;
if (firstA < firstB) return -1; //sort first names alphabetically
if (firstA > firstB) return 1;
return 0; //if they are equal
})
//print last names before first names with regex
let newArr = [];
for (let i = 0; i < testArr.length; i++) {
let variable = (testArr[i].replace(/([\w ]+), ([\w ]+)/g, "$2 $1"))
let comma = ","
newArr.push(`(${variable})`)
}
let finalStr;
finalStr = newArr.toString().replace(/[ ,.]/g, " ").toUpperCase();
// finalStr = finalStr.replace(/" "/g, ", ")
return finalStr
}
s = "Fred:Corwill;Wilfred:Corwill;Barney:Tornbull;Betty:Tornbull;Bjon:Tornbull;Raphael:Corwill;Alfred:Corwill";
console.log(meeting(s))
// expected result: "(CORWILL, ALFRED)(CORWILL, FRED)(CORWILL, RAPHAEL)(CORWILL, WILFRED)(TORNBULL, BARNEY)(TORNBULL, BETTY)(TORNBULL, BJON)"
Any help would be appreciated, I've spent about 5 hours on this problem.The regex I am using is to switch the last name's position with the first name's position (Fred Corwill) --> (Corwill Fred). If there is a regex for me to this other than the one I am using that you could suggest, maybe I could work around the problem this way too, so far everything I have tried has not worked other the one I am using here.
That looks much more complicated than it needs to be. After splitting by ;s, map each individual element to its words in reverse order, then join:
const s = "Fred:Corwill;Wilfred:Corwill;Barney:Tornbull;Betty:Tornbull;Bjon:Tornbull;Raphael:Corwill;Alfred:Corwill";
const output = s
.toUpperCase()
.split(';')
.sort((a, b) => {
const [aFirst, aLast] = a.split(':');
const [bFirst, bLast] = b.split(':');
return aLast.localeCompare(bLast) || aFirst.localeCompare(bFirst);
})
.map((name) => {
const [first, last] = name.split(':');
return `(${last}, ${first})`;
})
.join('');
console.log(output);
That's what you need:
const str = 'Fred:Corwill;Wilfred:Corwill;Barney:Tornbull;Betty:Tornbull;Bjon:Tornbull;Raphael:Corwill;Alfred:Corwill';
function formatString(string) {
const modifiedString = string.toUpperCase().replace(/(\w+):(\w+)/g, '($2, $1)');
const sortedString = modifiedString.split(';').sort().join('');
return sortedString;
}
console.log(formatString(str))
Using splits with maps and sorts
var s = "Fred:Corwill;Wilfred:Corwill;Barney:Tornbull;Betty:Tornbull;Bjon:Tornbull;Raphael:Corwill;Alfred:Corwill";
var res = s.split(/;/) // split into people
.map(x => x.split(/:/).reverse()) // split names, put last first
.sort((a, b) => a[0] === b[0] ? a[1].localeCompare(b[1]) : a[0].localeCompare(b[0])) // sort by last name, first name
.map(x => `(${x.join(', ')})`) // create the new format
.join(' ') // join the array back into a string
console.log(res);

Array not updated when iterating with "let element of array"

I fail to see why the first code below(titleCase1) does not capitalize every word, while the second one does(titleCase2).
var result1 = titleCase1('this is a new question in stackoverflow');
console.log('result1:',result1);
var result2 = titleCase2('this is a new question in stackoverflow');
console.log('result2:',result2);
function titleCase1(str) {
let words = str.split(" ");
for (let word of words) {
word = word[0].toUpperCase() + word.slice(1);
}
return words.join(" ");
}
function titleCase2(str) {
let words = str.split(" ");
for (let i = 0; i < words.length; i++) {
words[i] = words[i][0].toUpperCase() + words[i].slice(1);
}
return words.join(" ");
}
It seems that in the first case the words array is not updated and it has something to do with the let element of array iterator, but I do not understand why it does not work.
Strings, unlike arrays in JavaScript are value objects, not reference objects.
Here:
for (let word of words) {
word = word[0].toUpperCase() + word.slice(1);
}
You are declaring a word variable using let and it is scoped to the for loop. This variable is a copy of the substrings in your string. You reassign it at each iteration, but since it is a copy and not a reference to the substrings, your substring in the array words doesn't change, only the copy does.
However here:
for (let i = 0; i < words.length; i++) {
words[i] = words[i][0].toUpperCase() + words[i].slice(1);
}
You are changing the substring directly since you update each character by indexing them in the substring array.
Here is a much shorter way to do it with String.replace, a regex and an arrow function:
const titleCase = str => str.replace(/(?<=(\s+|^))\w/gi, x => x.toUpperCase());
console.log(titleCase('hello world'));
console.log(titleCase(' hello world'));
The regex (?<=(\s+|^)) is a positive lookbehind and makes sure that the pattern \w (word character) is preceeded by spaces or is located at the beginning of the string.
In the first code, you're reassigning a variable. Reassigning a variable, by itself, will never have any effect on anything else, at least in 99% of situations; it'll just mean that further references to word inside that for block will refer to the new value, rather than the old value. So, your word = ... won't affect anything, since you're not doing anything with that new word variable name later in the block. (after that iteration ends, the value stored in it will be unreferenced, and will soon be GC'd)
In the second code, you're mutating an object: words[i] = will mean that further accesses to index i of words will return the new value.
word is not an array. It is just a word. and you are returning words with joining them which is already a string with no space join will have no effect
function titleCase(str) {
let a=[];
let words = str.split("");
for (let word of words) {
a.push(word.toUpperCase());
}
return a.join("");
}
console.log(titleCase("hello"))

Remove all consonants in a string before a vowel then add a character

I want to remove all consonants in a string before the occurrence of a vowel and then replace it with an 'r'.
This means that 'scooby' will become 'rooby', 'xylographer' will become 'rographer' and so on. This is the algorithm I came up with:
1. Check if input type is not a string.
2. Use a variable(newStr) to hold lowercase conversion and splitted word.
3. Declare a variable(arrWord) to hold the length of the array.
4. Another variable called regex to check if a string starts with a consonant
5. Variable newArr holds the final result.
6. Search through the array, if the string does not start with a consonant
join it and return it.
7. Else keep looking for where the first vowel occurs in the word.
8. When found, remove all characters(consonants) before the vowel occurence
and replace them with an r.
9. Join the array together.
I have been able to come up with this:
const scoobyDoo = str => {
if(typeof str !== 'string'){
return 'This function accepts strings only';
}
let newStr = str.toLowerCase().split('');
let arrWord = newStr.length;
let regex = /[aeiou]/gi;
for (let i = 0; i < arrWord; i++){
if (newStr[0].match(regex)) {
let nothing = newStr.join('');
return nothing;
}
else {
let vowelIndex = newStr.indexOf(str.match(regex)[0]);
newStr.splice(0, vowelIndex, 'r');
return newStr.join('');
}
}
}
console.log(scoobyDoo('scOoby'));
I tested out the program again by capitalizing the first vowel index and instead of 'rooby' I get 'rscooby'. Why is that so?
Can you once try with following code in your else and see the changes
else {
var vowelIndex = newStr.indexOf(str.match(regex)[0]);
newStr.splice(0, vowelIndex, 'r');
return newStr.join("");
}
Is it not much easier like this? Or am I missing something??
'xylographer'.replace(/^\s*[^aieou]+(?=\w)/i,function(m,o,s){return "r"})
//"rographer"
'scooby'.replace(/^\s*[^aieou]+(?=\w)/i,function(m,o,s){return "r"})
//"rooby"
you could just use one reg expression for the whole algorithm and no need to split your string no more.
regexp to use.
/^[^aouie, AOUIE]+(?=[aouie, AOUIE])/g
of course you can readjust regexp to suit you more but this will get your main requirement.
On the line immediately after the else statement, I just called .toLowerCase() on it and it was fixed:
let vowelIndex = newStr.indexOf(str.match(regex)[0].toLowerCase());
I like keeping my code simple and readable
function pattern(str){
var vowelIndex = str.indexOf(str.match(/[aeiou]/)); //returns index of first vowel in str
return "r" + str.slice(vowelIndex);
}
console.log(pattern('xylographer'));

Javascript regex replace with different values

I'd like to know if it is possible to replace every matching pattern in the string with not one but different values each time.
Let's say I found 5 matches in a text and I want to replace first match with a string, second match with another string, third match with another and so on... is it achievable?
var synonyms = ["extremely", "exceedingly", "exceptionally", "especially", "tremendously"];
"I'm very upset, very distress, very agitated, very annoyed and very pissed".replace(/very/g, function() {
//replace 5 matches of the keyword every with 5 synonyms in the array
});
You may try to replace the matches inside a replace callback function:
var synonyms = ["extremely", "exceedingly", "exceptionally", "especially", "tremendously"];
var cnt = 0;
console.log("I'm very upset, very distress, very agitated, very annoyed and very pissed (and very anxious)".replace(/very/g, function($0) {
if (cnt === synonyms.length) cnt = 0;
return synonyms[cnt++]; //replace 5 matches of the keyword every with 5 synonyms in the array
}));
If you have more matches than there are items in the array, the cnt will make sure the array items will be used from the first one again.
A simple recursive approach. Be sure your synonyms array has enough elements to cover all matches in your string.
let synonyms = ["extremely", "exceedingly", "exceptionally"]
let yourString = "I'm very happy, very joyful, and very handsome."
let rex = /very/
function r (s, i) {
let newStr = s.replace(rex, synonyms[i])
if (newStr === s)
return s
return r(newStr, i+1)
}
r(yourString, 0)
I would caution that if your replacement would also match your regex, you need to add an additional check.
function replaceExpressionWithSynonymsInText(text, regX, synonymList) {
var
list = [];
function getSynonym() {
if (list.length <= 0) {
list = Array.from(synonymList);
}
return list.shift();
}
return text.replace(regX, getSynonym);
}
var
synonymList = ["extremely", "exceedingly", "exceptionally", "especially", "tremendously"],
textSource = "I'm very upset, very distress, very agitated, very annoyed and very pissed",
finalText = replaceExpressionWithSynonymsInText(textSource, (/very/g), synonymList);
console.log("synonymList : ", synonymList);
console.log("textSource : ", textSource);
console.log("finalText : ", finalText);
The advantages of the above approach are, firstly one does not alter the list of synonyms,
secondly working internally with an ever new copy of the provided list and shifting it,
makes additional counters obsolete and also provides the opportunity of being able to
shuffle the new copy (once it has been emptied), thus achieving a more random replacement.
Using the example you've provided, here's what I would do.
First I would set up some variables
var text = "I'm very upset, very distress, very agitated, very annoyed and very pissed";
var regex = /very/;
var synonyms = ["extremely", "exceedingly", "exceptionally", "especially", "tremendously"];
Then count the number of matches
var count = text.match(/very/g).length;
Then I would run a loop to replace the matches with the values from the array
for(var x = 0; x < count; x++) {
text = text.replace(regex, synonyms[x]);
}
You can do it with the use of Replace() function, where you use 'g' option for global matching (finds all occurrences of searched expression). For the second argument you can use a function which returns values from your predefined array.
Here is a little fiddle where you can try it out.
var str = "test test test";
var rep = ["one", "two", "three"];
var ix = 0;
var res = str.replace(/test/g, function() {
if (ix == rep.length)
ix = 0;
return rep[ix++];
});
$("#result").text(res);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p id="result">
Result...
</p>
Yes it is achievable. There may be a more efficient answer than this, but the brute force way is to double the length of your regex. i.e. Instead of searching just A, search (/A){optionalText}(/A) and then replace /1 /2 as needed. If you need help with the regex itself, provide some code for what you're searching for and someone with more rep than me can probably comment the actual regexp.

Javascript split array

I have a JavaScript array which contain the staff's Chinese and English names.
Example:
XXX MA Yo-Yo
Where XXX represents the Chinese name: 馬友友.
I want to split this into two parts by using the 1st space " " as an indicator.
for (i = 0; i < /* ... */)
{
w_temp = arr[i];
w_name = w_temp[1].split(' ', 1);
/* ... */
}
w_name[0] successfully returns 馬友友. But w_name[1] returns undefined, which cannot return MA Yo-Yo.
How can I split it into two parts?
Replace your existing w_name = ... line with something like this:
w_name = w_temp[1].split(' ');
w_name = [w_name[0], w_name.slice(1).join(' ')];
The ,1 you had earlier meant to stop parsing as soon as it came to the first space. This is not what you want; you want the part before the first space as one item and the part after as another. The new code parses all of the elements. After that, it sets it to an array consisting of:
The already-existing first element, and
The parts after the first element re-joined.
You have
split(' ', 1)
The 1 means to return at most one part. You should just ommit that or change it to two if thats what you need.
Because you invoke split method with limit = 1, then w_name has only 1 item.
In addition, yours input string has 2 whitespace, therefore, if you use split without limit parameter, w_name will contains 3 items ('XXX', 'CHAN', and 'Tai-Man').
I think you should use this:
var idx = str.indexOf(' ');
if (idx != -1) {
var cn_name = str.substring(0, idx);
var en_name = str.substring(idx + 1);
}
Try this
for (var i = 0; i < arr.length; i++) {
var w_temp = arr[i];
// assuming w_temp contains an array where the second item
// is the full name string
var parts = w_temp[1].match(/^(.+?) (.+)$/);
var cn_name = parts[1];
var en_name = parts[2];
}

Categories

Resources