I am attempting to take a given string and replace a given number in that string with a character. Specifically:
5 is to be replaced with "S"
1 is to be replaced with "I"
0 is to be replaced with "O"
(this is a Kata exercise)
I have written a function which should:
Take the string and convert it into an array
Loop over the array
Replace each instance of the aforementioned numbers with the appropriate replacements using .replace()
Return the joined string.
My code is as appears below
Function correct(string) {
let array = string.split('')
for (let i = 0; i < array.length; i++) {
array[i].replace('5', 'S')
array[i].replace('0', 'O')
array[i].replace('1', 'I')
}
return array.join('');
}
The function returns the string exactly as initially provided, unchanged. I suspect my issue is with the way I've used the .replace() method within the loop, or the index positions declared.
String.prototype.replace returns a new string and does not mutate the variable it was executed on.
That's why you need to assign the result of replacement somewhere.
To fix your code just do the following with each replacement:
array[i] = array[i].replace('5', 'S');
Note 1: since array[i] is always a single character, there is no need in replace, because you can just compare like so:
if (array[i] === '5') {
array[i] = 'S';
}
or oneliner:
array[i] = array[i] === '5' ? 'S' : array[i];
Note 2: for loop for a replacement is not a clean code. JavaScript is very flexible and provides much better solutions to the problem. Eg. String.prototype.replaceAll.
Try this :
const inputStr = 'AB5DE0G1H';
function correct(string) {
return string.replaceAll('5', 'S').replaceAll('0', 'O').replaceAll('1', 'l')
}
console.log(correct(inputStr));
You can do with simple regex replace() based on your key=>value like this,
const key_to_replace = {
'5': 'S',
'1': 'I',
'0': 'O'
}
const correct = (str) =>
str.replace(/./g, (m) => key_to_replace[m] ?? m);
console.log(correct("this 5is a0 test1 with 55abc"))
Related
I was taking on a JS challenge to take a first/last name string input and do the following:
swap the first letter of first/last name
convert all characters to lowercase, except for the first characters, which need to be uppercase
Example:
input: DonAlD tRuMp
output: Tonald Drump
The following is the code I came up with:
const input = prompt("Enter a name:")
function switchFirstLetters(input) {
let stringArray = input.split('');
for(let i=0; i < stringArray.length; i++) {
if(stringArray[i - 1] === ' ') {
[stringArray[0], stringArray[i]] = [stringArray[i], stringArray[0]]; // destructuring
}
}
return result = stringArray.join('');
}
let swappedString = switchFirstLetters(input);
function capFirstLetters(swappedString) {
let stringArray = swappedString.toLowerCase();
stringArray = stringArray.split('');
stringArray[0] = stringArray[0].toUpperCase();
for(let i=0; i < stringArray.length; i++) {
if(stringArray[i - 1] === ' ') {
stringArray[i] = stringArray[i].toUpperCase();
}
}
return result = stringArray.join('');
}
let finalString = capFirstLetters(swappedString);
console.log(finalString);
My thought process for the switchFirstLetters function was:
Create an array from the string parameter
Run through the array length. If the value of the element prior the current element is equal to ' ', use destructuring to swap the current element with the element at index 0
Concatenate elements into a new string and return that value
My thought process for the capFirstLetters function:
Convert all characters in the string to lowercase (this could be handled outside of the function as well)
Create an array from the new, lowercase string
Make character at index 0 be uppercase (this could also be integrated into the for loop)
Run through the array length. If the value of the element prior to the current element is equal to ' ', convert that element to uppercase.
Concatenate array elements into a new string
The code works, but I'm still early in my coding journey and realize it's likely not an ideal solution, so I was wondering if anyone here could help me optimize this further to help me learn. Thanks!
You could also use a regular expression to replace the first letters:
let name = "DonAlD tRuMp";
let result = name.toLowerCase().replace(/(\S)(\S*\s+)(\S)/g, (_, a, b, c) =>
c.toUpperCase() + b + a.toUpperCase()
);
console.log(result);
The regular expression uses \S (a non-white-space character), \S* (zero or more of those), \s+ (one or more white-space characters) and parentheses to create capture groups. These three groups map to a,b,c parameters in the callback function that is passed to replace as second argument. With these parts the replacement string can be constructed. Both the capitalisation and the switch happen in the construction.
If the replace function is a little overwhelming, my attempt introduces the for-of loop, the substring string method, array slice as well as the && short circuit evaluation. You should also be aware you can access a given character of a string using the square bracket syntax, just like array, but string has it's own set of methods which tend to have different names.
Definitely take a look at the replace function, to make your v2.
const rawNameInput = "DonAlD jUnior tRuMp"
const nameInput = rawNameInput.trim()
const rawNameWords = nameInput.split(" ")
const nameWords = []
for (const word of rawNameWords) {
const first = word[0].toUpperCase()
const rest = word.substring(1).toLowerCase()
nameWords.push(first + rest)
}
const middleNames = nameWords.slice(1, -1).join(" ")
const lastIdx = nameWords.length - 1
const newFirstName = nameWords[lastIdx][0] + nameWords[0].substring(1)
const newLastName = nameWords[0][0] + nameWords[lastIdx].substring(1)
console.log(`${newFirstName} ${middleNames && middleNames + " "}${newLastName}`)
I am trying to make the first letter of each word capitalized via toUpperCase method and the rest of the word is in the lower case via the toLowerCase method. But I am missing something... Why temp value is not matching with result[1][0] even if I am using that method for both?
Note: I know about other ways (map, replace, etc) for my solution, but I want to just use a for-loop with toUpperCase and toLowerCase methods.
function titleCase(str) {
let regex = /[^0-9\s]+/g;
var result = str.match(regex);
let temp = "";
for (let i = 0; i < result.length; i++) {
for (let j = 0; j < result[i].length; j++) {
result[1][0] = result[1][0].toUpperCase();
temp = result[1][0].toUpperCase();
}
}
console.log(temp); // Output is 'A'
console.log(result[1][0]); //Output is 'a'
// Normally 'temp' and 'result[1][0]' should be equal, but one returns a lowercase character and the other an uppercase character.
return str;
}
titleCase("I'm a little tea pot");
Your problem is not with the toUppercase(), it is with the reference.
When referencing result[1][0], why are you including the 0? You already have the second character with result[1]
result[1] === 'a'. No need to include the [0] as well.
Change your code so it looks like this:
function titleCase(str) {
let regex = /[^0-9\s]+/g;
var result = str.match(regex);
let temp = "";
result[1] = result[1].toUpperCase();
temp = result[1].toUpperCase();
console.log(temp); // Output is 'A'
console.log(result[1]); //Output is also 'A'
// both now equals capital A
return str;
}
titleCase("I'm a little tea pot");
EDIT:
Updating the function to uppercase the first letter of the word.
We can use ES6, which would make this really simple:
const capitalize = (string = '') => [...string].map((char, index) => index ? char : char.toUpperCase()).join('')
Use it: capitalize("hello") returns 'Hello'.
First we convert the string to an array, using the spread operator, to get each char individually as a string. Then we map each character to get the index to apply the uppercase to it. Index true means not equal 0, so (!index) is the first character. We then apply the uppercase function to it and then return the string.
If you want a more object oriented approach, we can do something like this:
String.prototype.capitalize = function(allWords) {
return (allWords) ?
this.split(' ').map(word => word.capitalize()).join(' ') :
return this.charAt(0).toUpperCase() + this.slice(1);
}
Use it: "hello, world!".capitalize(); returns "Hello, World"
We break down the phrase to words and then recursive calls until capitalising all words. If allWords is undefined, capitalise only the first word meaning the first character of the whole string.
I was tried to change a specific character in the string but strings are immutable in JS so this does not make sense.
been working on a school problem, and haven't been able to figure it out. Any help is appreciated!
Write a function named countBrackets that accepts a string
and returns the count of square bracket and curly bracket
characters in the string. That is, it should count occurrences of
these four characters “{ } [ ]”. Use function expression syntax.
var countBrackets = function(s){
let sum = 0
for(let i = ""; i == s ; i++ )
if(i ==="{}[]"){
sum+=i
}
return sum}
console.log(countBrackets("[123],{456},[{}]")) //8
console.log(countBrackets("Test string")) // 0
I'm a little confused on how I'm supposed to get it to count a string I guess.
You can use a global regex (regular expression) matching for this. The regex is between / / followed by the g flag to make it global (otherwise it only returns the first result it finds and stops).
Within the regex, | is the OR operator, so you match for /{|}|[|]/
Since [ and ] have special meaning in regular expressions you need to escape those using a \ so your total regex becomes /{|}|\[|\]/g.
This returns an array of matches, I called the function findBrackets.
To get the number of brackets, the function countBrackets just returns the .length of that array.
const findBrackets = str => str.match(/{|}|\[|\]/g);
const countBrackets = str => findBrackets(str) ? findBrackets(str).length : 0;
console.log(findBrackets('qw[e}rt[y]ui{}o{p'));
console.log(countBrackets('qw[e}rt[y]ui{}o{p'));
console.log(countBrackets('no brackets here'));
Edit: seeing the code you posted, you decided to use a for-loop to loop over your string, which is a totally valid solution.
Note that in my above example
const findBrackets = str => str.match(/{|}|\[|\]/g);
Is basically the same but a newer way of writing functions (with a few nuances)
I could have written:
var findBrackets = function(str) {
return str.match(/{|}|\[|\]/g);
}
instead which would be almost the same.
If you want to loop over a string, you can access a letter in the string by using square bracket notation, so for example
const testString = 'hello';
console.log(testString[1]);
Would output the letter 'e'.
So to use this in a function:
const countBrackets = (str) => {
let counter = 0;
for (let i = 0; i < str.length; i++) {
if (str[i] === '[' || str[i] === ']' || str[i] === '{' || str[i] === '}') {
counter++;
}
}
return counter;
}
console.log(countBrackets('qw[e}rt[y]ui{}o{p'));
Here you loop over the string from 0 to < length of the string and check every letter of it, by seeing if str[i] is {, }, [ or ], and if it is you increment a counter. After that's done you return the final count.
I want to write a function to change the characters in a string at even indices to uppercase. I don't want my program to count the spaces as an even index, even if it falls on an even index.
For example: 'This is a test' => 'ThIs Is A TeSt'
I originally had this solution, but I could not get it to work to ignore the space characters when counting the even indices.
function toWeirdCase(string) {
return string.split("").map((x,i) => i%2=== 0 && x!== " " ? x.toUpperCase() : x).join("")
}
This is my second attempt and I don't know why the string elements aren't actually changing to uppercase. Any help on this would be appreciated. It is just returning the original string.
function toWeirdCase(string) {
let indexCount = 0;
let isSpace = false;
for (let i = 0; i < string.length; i++) {
if (string[i] === " ") {
isSpace = true;
}
if (indexCount % 2 === 0 && !isSpace) {
string[indexCount] = string[indexCount].toUpperCase();
}
indexCount++;
isSpace = false;
}
return string;
}
Answer:
You can use a modified reduce function that utilizes a closure as a character counter. This has the benefit of completing the transformation in one pass:
["", ...str].reduce((n =>
(r, c) => r += /\s/.test(c) ? c : c[`to${n++ & 1 ? "Lower" : "Upper"}Case`]())(0)
);
Example:
const biUpperCase = str => ["", ...str].reduce((n =>
(r, c) =>r += /\s/.test(c) ? c : c[`to${n++ & 1 ? "Lower" : "Upper"}Case`]())(0)
);
let test = biUpperCase("This is a Test");
console.log(test);
Explanation:
n is a character counter that keeps track of all non-space characters. You can think of this as an additional index that only worries about non-space characters.
We use this to determine whether or not a character is an even or odd non-space character by performing bitwise AND ( n & 1 ) or, alternatively, by performing a modulus operation ( n % 2 )
r is the accumulator in the Array.prototype.reduce method. This is what is returned by our reduce method.
Since there was no secondary parameter to Array.prototype.reduce, the first index of the Array is used as the accumulator.
This is why we perform ["", ...str] instead of simply [...str].
Syntactically we could also have written [...str].reduce( fn , "" ) instead of ["", ...str].reduce( fn ), but this would alter our succinct code.
c is the current character that we are looking at within the string array. We use RegExp.prototype.match to determine if it's a space character.
if it is we simply add the space to r ( our accumulated string )
if it is not we add a transformed character to r ( our accumulated string )
To determine which case transformation( upper or lower ) should be applied we check if n ( our character counter ) is even or odd.
if n++ & 1 is truthy the case is lower
if n++ & 1 is falsy the case is upper
Aside:
You'll notice in the snippet and code I provided that I changed your parameter name string to str. The reason for this is because String is a built-in Constructor in JavaScript and it's best to never purposefully "cross the streams" when naming variables.
In the current way that you're attempting to use this variable it makes no difference since it's properly scoped, and truthfully it is up to you if you want to take my advice. Just be aware that it could lead to an annoying, invisible problem.
Hope this Helps! Happy Coding!
You could rewind the index counter for a single word.
function toWeirdCase(string) {
return Array
.from(
string,
(i => x => (/[a-z]/i.test(x) ? i++ : (i = 0)) % 2 ? x : x.toUpperCase())
(0)
)
.join('');
}
console.log(toWeirdCase('This is a test')); // 'ThIs Is A TeSt'
A string in javascript is immutable so you will need to do something like :
let test = 'This is a test';
test = toWeirdCase(test); //Here you assign the result
And here is an example solution which ignores spaces in the count
function toWeirdCase(string) {
let count = 0;
return string.split("").map((x) => {
if(x !== " ")
count++;
if(count%2 === 0) return x.toUpperCase();
else return x;
}).join("")
}
let test = 'This is a test';
test = toWeirdCase(test);
console.log(test); //THiS iS a TeSt
Like the comments mention, strings in Javascript are immutable. That being said, you can break down the input string on whitespace, do the transformations, and join back into a string, something like this -
function toWeirdCase(sentence) {
return sentence
.split(' ')
.map(word => word
.split('')
.map((c, i) => i % 2 ? c : c.toUpperCase())
.join('')).join(' ');
}
You could store the number of spaces in a variable in the functions scope.
function toWeirdCase(string) {
let spaceCount = 0;
// Personal preference: I like the reduce fn for this, but a similar thing could be achieved with map
return string.split('').reduce((value, letter, index) => {
if (letter === ' ') spaceCount++;
return value += ((index - spaceCount) % 2)
? letter
: letter.toUpperCase();
},'')
}
This returns the leter if the index ingoring the space count has a remainder when divided by 2.
You can achieve this like so:
const str = "this is a test";
function toWeirdCase(str) {
return str.split(" ").map(word => (
[...word].map((c, i) => i % 2 ?
c.toLowerCase() :
c.toUpperCase())).join("")).join(" ");
}
console.log(toWeirdCase(str));
Updated: to set odd indexes toLowerCase() to handle edge cases like acronyms (ie: currency acronyms; "CA", "USD")
Hope this helps,
I am running through some exercises and run into this on codewars. Its a simple exercise with Instructions to create a function called shortcut to remove all the lowercase vowels in a given string.
Examples:
shortcut("codewars") // --> cdwrs
shortcut("goodbye") // --> gdby
I am newbie so I thought up this solution. but it doesn't work and I have no idea why
function shortcut(string){
// create an array of individual characters
var stage1 = string.split('');
// loop through array and remove the unneeded characters
for (i = string.length-1; i >= 0; i--) {
if (stage1[i] === "a"||
stage1[i] === "e"||
stage1[i] === "i"||
stage1[i] === "o"||
stage1[i] === "u") {
stage1.splice(i,1)
;}
};
// turn the array back into a string
string = stage1.join('');
return shortcut;
}
My gut is telling me that it will probably something to like split and join not creating "true" array's and strings.
I did it at first with a regex to make it a little more reusable but that was a nightmare. I would be happy to take suggestions on other methods of acheiving the same thing.
You are returning the function itself, instead of returning string
Using regex:
var str = 'codewars';
var regex = /[aeiou]/g;
var result = str.replace(regex, '');
document.write(result);
if interested in Regular Expression ;)
function shortcut(str) {
return str.replace(/[aeiou]/g, "");
}