Trying to create a function that replaces letters of a string [duplicate] - javascript

This question already has answers here:
How do I replace a character at a particular index in JavaScript?
(30 answers)
Closed last month.
I'm doing an exercise where I need to create a function that takes phrase and letter as parameters, and changes the letters of the phrase that are equal to the parameter letter by '*'
function changingLetters(phrase, letter) {
for (let i = 0; i < phrase.lenght; i++) {
if (phrase[i] === letter) {
phrase[i] = '*'
}
}
return phrase
}
console.log(changingLetters('This is a test','s'))
It's returning the original sentence...

Strings in JavaScript are immutable, meaning you can't change individual characters through the index.
You can convert the string to an array, then set the indicies on the array, and convert it back to a string at the end.
function changingLetters(phrase, letter) {
const phraseArray = [...phrase];
for (let i = 0; i < phrase.length; i++) {
if (phraseArray[i] === letter) {
phraseArray[i] = '*'
}
}
return phraseArray.join("");
}
console.log(changingLetters('This is a test','s'))
You also had a typo phrase.lenght -> phrase.length, but that was not the cause of the main issue.
If you want a simple solution,
function changingLetters(phrase, letter) {
return phrase.replaceAll(letter, "*");
}
console.log(changingLetters('This is a test','s'))
but i think the point of the exercise is that you're supposed to implement this functionality yourself.

This code will not work as expected. JavaScript strings are immutable, meaning that their values cannot be modified once they are created. So when you try to change the value of a character in the string using the code phrase[i] = '*', it will throw an error.
Here is a possible way to write the function using split(), join(), and map() methods
function changingLetters(phrase, letter) {
return phrase.split('').map(char => char === letter ? '*' : char).join('');
}
console.log(changingLetters('This is a test','s'));
This code will split the string into an array of individual characters, then it will iterate over that array and use the map function to return a new array with the character replaced by '*' if the original character is the same as the letter you passed. and then join back the array of characters to form a string again.
You can also use replace() method
function changingLetters(phrase, letter) {
return phrase.replace(new RegExp(letter,'gi'),'*');
}
console.log(changingLetters('This is a test','s'));
the replace(new RegExp(letter,'gi'),'') will replace all occurences of letter with '', 'gi' makes the replace operation case-insensitive and global, i.e it will replace all occurence of letter regardless of the case and will match all occurences not just the first one.

Related

Reverse a string except for the characters contained within { } with javascript

I need to reverse a string except the characters inside of "{}". I know how to reverse a string but I'm not sure how to create the exception. Please help.
function reverseChar(string2){
let string2Array = string2.split('');
let newArray = [];
for(let x = string2Array.length-1; x >= 0; x--){
newArray.push(string2Array[x])
}
console.log(newArray)
}
reverseChar("ab{cd}efg")
reverseChar("ab{cd}ef{gh}i")
Or, maybe, this is what you want?
function reverse(str) {
return str.split("").reverse().join("").replace(/}\w+\{/g,a=>reverse(a))
}
console.log(reverse("ab{cd}efg"))
console.log(reverse("ab{cd}ef{gh}i"))
The RegExp /}\w+\{/g will find any string of characters and numbers (\w+) that is enclosed by } and {. These patterns will exist after the whole string is reverse()-d initially. In the callback function to the String.replace() method the matched string will then be reversed again.
You can try this logic:
Get all the parts
If the part does not have special character, reverse it and set it.
Reverse the parts array
Join all the parts back and return it
function reverseChar(string2) {
const regex = /(\w+(?=\{|$)|\{\w+\})/g
return string2.match(regex)
.map((str) => /\{/.test(str) ? str : str.split("").reverse().join(""))
.reverse()
.join("")
}
console.log(reverseChar("ab{cd}efg"))
console.log(reverseChar("ab{cd}ef{gh}i"))

Splitting a CSV string but not certain elements javascript [duplicate]

This question already has answers here:
How to parse CSV data?
(14 answers)
Closed 6 months ago.
If given an comma separated string as follows
'UserName,Email,[a,b,c]'
i want a split array of all the outermost elements so expected result
['UserName','Email', '[a,b,c]']
string.split(',') will split across every comma but that wont work so any suggestions? this is breaking a CSV reader i have.
I wrote 2 similar answers, so might as well make it a 3rd instead of referring you there. It's a stateful split. This doesn't support nested arrays, but can easily made so.
var str = 'UserName,Email,[a,b,c]'
function tokenize(str) {
var state = "normal";
var tokens = [];
var current = "";
for (var i = 0; i < str.length; i++) {
c = str[i];
if (state == "normal") {
if (c == ',') {
if (current) {
tokens.push(current);
current = "";
}
continue;
}
if (c == '[') {
state = "quotes";
current = "";
continue;
}
current += c;
}
if (state == "quotes") {
if (c == ']') {
state = "normal";
tokens.push(current);
current = "";
continue;
}
current += c;
}
}
if (current) {
tokens.push(current);
current = "";
}
return tokens;
}
console.log(tokenize(str))
You can do this by matching the string to this Regex:
/(^|(?<=,))\[[^[]+\]|[^,]+((?=,)|$)/
let string = '[a,b,c],UserName,[1,2],Email,[a,b,c],password'
let regex = /(^|(?<=,))\[[^[]+\]|[^,]+((?=,)|$)/g
let output = string.match(regex);
console.log(output)
The regex can be summarized as:
Match either an array or a string that's enclosed by commas or at the start/end of our input
The key token we're using is alternative | which works as a sort of either this, or that and since the regex engine is eager, when it matches one, it moves on. So if we match and array, then we move on and don't consider what's inside.
We can break it down to 3 main sections:
(^|(?<=,))
^ Match from the beginning of our string
| Alternatively
(?<=,) Match a string that's preceded by a comma without returning the comma. Read more about positive lookaround here.
\[[^[]+\] | [^,]+
\[[^[]+\] Match a string that starts with [ and ends with ] and can contain a string of one or more characters that aren't [
This because in [1,2],[a,b] it can match the whole string at once since it starts with [ and ends with ]. This way our condition stops that by removing matches that also contain [ indicating that it belongs the second array.
| Alternatively
[^,]+ Match a string of any length that doesn't contain a comma, for the same reason as the brackets above since with ,asd,qwe, technically all of asd,qwe is enclosed with commas.
((?=,)|$)
(?=,) Match any string that's followed by a comma
| Alternatively
$ Match a string that ends with the end of the main string. Read here for a better explanation.

How can I check a word is made of letters in different array

I am writing a word game in Vue.
You start with a string of random characters and you have to input a word that can be made from that string, eg for "ABEOHSTD" the user can enter "BASE" for a score of 4.
I have an external word list in a .txt file (which I also can't get working, but that's a separate issue) I need to verify the words against, but I'm having trouble verifying the words can be made from the given random string.
I don't know how I'd approach making sure each letter can only be used as many times as it appears in the array, or even store the scores but I just want to get this first part working.
I have tried splitting both the entered word and random string into an array of each character, looping through the array and checking if each character in the user entered string is included in the random string array.
splitUserCurrentWord = this.userAttemptedWord.split("");
for (var i = 0; i <= splitUserCurrentWord.length; i++) {
if (this.randomStringForGame.split("").includes(splitUserCurrentWord[i])) {
return true;
//i++
}
else {
return false;
}
}
}
Currently I expect to resolve to true if all the letters in the user inputted word are present in the random string array, but it seems to only resolve to true or false based on the first letter of the array, which isn't good because as long as the first letter is in the random string array it will register as true/correct.
jsfiddle of the entire thing so far:
https://jsfiddle.net/sk4f9d8w/
Your return statement is exiting the loop after the 1st iteration.
One way to do it is to use Array.every to verify all the letters and String.includes to check if the letter is part of the accepted String
const randomString = "ABEOHSTD";
console.log(isWordValid(randomString, "BASE"));
console.log(isWordValid(randomString, "BASEU"));
function isWordValid(validLetters, attemtedWord) {
const attemptedWordSplitted = attemtedWord.split("");
return attemptedWordSplitted.every(attemptedLetter => validLetters.includes(attemptedLetter));
}
If you don't allow to reuse the same letter multiple times, you need another approach by deleting the used letter from the list of acceptable letters
const randomString = "ABEOHSTD";
console.log(isWordValid(randomString, "BASE"));
console.log(isWordValid(randomString, "BAASE"));
console.log(isWordValid(randomString, "BASEU"));
function isWordValid(validLetters, attemptedWord) {
const validLettersSplitted = validLetters.split("");
const attemptedWordSplitted = attemptedWord.split("");
return attemptedWordSplitted.every(attemptedLetter => {
const letterIndex = validLettersSplitted.indexOf(attemptedLetter);
if(letterIndex > -1){
validLettersSplitted.splice(letterIndex, 1);
return true;
} else {
return false
}
});
}
You are on the right way, You need to check each letter in the user word and check if they are in the random word. If one letter is in the random word, you remove it from the random word so it can't be use twice. :
let randomWord = "ABEOHSTD";
let userWordThatFail = "BAASE";
let userWord = "BASE";
// optionnaly, uppercase both words.
// we split into letters to make it easiers to process
let randomLetters = randomWord.split('');
let userLetters = userWord.split('');
let score = 0;
//we parse each letter of the user input
userLetters.forEach((letter) => {
// the letter exists in the random word.
let indexOfTheCurrentLetter = randomLetters.indexOf(letter);
// the letter exists, we remove it and increment the score.
if(indexOfTheCurrentLetter !== -1) {
randomLetters.splice(indexOfTheCurrentLetter, 1);
score++;
}
});
// the user input contains letters that are not in the random input.
if(score < userLetters.length) {
console.log('fail');
} else {
console.log('win : ' + score);
}
A simple approach might be to iterate the list of valid characters for every character encountered in the string to test. Using string.includes would fall into this bracket. Problematically, that's O(n_validchars * n_testchars) time-complexity for each comparison. This might not be desirable for longer strings.
The JavaScript Set object can help here.
With this higher-order function (that leans heavily on the iterable nature of a string), you can generate a reusable function for a set of valid characters:
function testFor(validChars) {
const charSet = new Set(validChars);
return testString =>
Array.prototype.every.call(testString, c => charSet.has(c));
}
// And to use it:
const testForABC = testFor("ABC"); //returns a function
console.log(testForABC("AABBCC")); //true
console.log(testForABC("abc")); //false
Now, because Set lookups are O(1), we're looking at O(n) complexity where n is the length of the string we're testing. Much better.

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));

How to check if one element of an array matches another element in same array?

Very new to javascript so bear with me...
I need to check one element of an array(arr[1]), which contains a string, against another element of the same array(arr[0]) to determine if any letters included in element arr[1] are included in arr[0]. Those letters can be in any order, upper or lower case, and don't have to occur the same number of times (i.e. arr[0]="hheyyy" and arr[1]="hey" is fine). This is what i have (which works) but I was curious if anyone has a better/more simple way of doing this? -thanks in advance.
function mutation(arr) {
//splits the array into two separate arrays of individual letters
var newArr0 = arr.join('').toLowerCase().split('').slice(0,arr[0].length);
var newArr1 = arr.join('').toLowerCase().split('').slice(arr[0].length);
var boolArr = [];
//checks each letter of arr1 to see if it is included in any letter of arr0
for(var i = 0; i < newArr1.length; i++)
boolArr.push(newArr0.includes(newArr1[i]));
//results are pushed into an array of boolean values
if (boolArr.indexOf(false) !==-1)
return false; //if any of those values are false return false
else return true;
}
mutation(["hello", "hey"]); //returns false
You could use a regular expression:
function mutationReg(arr) {
return !arr[1].replace(new RegExp('['+arr[0].replace(/(.)/g,'\\\\$1')+']', "gi"), '').length;
}
This escapes every character in the second string with backslash (so it cannot conflict with regular expression syntax), surrounds it with square brackets, and uses that as a search pattern on the first string. Any matches (case-insensitive) are removed from the result, so that only characters are left over that don't occur in the second string. The length of the result is thus an indication on whether there was success or not. Applying the ! to it gives the correct boolean result.
This might not be the fastest solution.
Here is another ES6 alternative using a Set for good performance:
function mutation(arr) {
var chars = new Set([...arr[0].toLowerCase()]);
return [...arr[1].toLowerCase()].every (c => chars.has(c));
}
You can use Array.from() to convert string to an array, Array.prototype.every(), String.prototype.indexOf() to check if every charactcer in string converted to array is contained in string of other array element.
var arr = ["abc", "cab"];
var bool = Array.from(arr[0]).every(el => arr[1].indexOf(el) > -1);
console.log(bool);

Categories

Resources