This test objective is to take the first consonant (or consonant cluster) of an English word, moves it to the end of the word and suffixes an "ay". If a word begins with a vowel you just add "way" to the end.
My main issue is to iterate through the string until it reaches a vowel and put the first consonants letters to the end of the string.
I’m having trouble iterating through the string until it reaches a vowel. How do you iterate a string until it stops at the first vowel? How do you get all of the first consonant letters before it reaches vowel? I iterate the string by using the for loop, and I use the “if” statement if the first letters are consonant.
function translatePigLatin(str) {
var vowel = /[aeiou]/g;
var cons = /[^aeiou]/g;
console.log(cons.test(str[2]))
var consonants = [];
var index = str.charAt(0);
console.log(str.slice(1, str.length))
for(var i = 0; i < str.length; i++){
console.log(str[i])
if(cons.test(str[i])){
consonants.push(str.charAt(i));
console.log(consonants)
var slice = str.slice(consonants.length, str.length);
}
}
return consonants + 'ay';
}
translatePigLatin("glove");
I would focus on just finding the index of the first vowel. Then you can test whether that index is 0 or something else. If it's zero, just add the way otherwise slice on that index:
function translatePigLatin(str) {
const vowels = ['a', 'e', 'i', 'o', 'u'];
let ind = [...str.toLowerCase()].findIndex(s => vowels.includes(s))
return ind
? str.slice(ind) + str.slice(0, ind) + 'ay' // doesn't start with vowel
: str + 'way'
}
console.log(translatePigLatin('glove'))
console.log(translatePigLatin('apple'))
console.log(translatePigLatin('Mark'))
console.log(translatePigLatin('Javascript'))
I'm not sure what the pig latin rules are for the edge case of a word with no vowels like rhythm.
I think you should break the problem into some basic cases, like I did in the code below:
Check if the first letter is a vowel; if true, just add 'way' to the end of the word and break the loop
If the current letter is a consonant (that means the first condition is not true), we just continue iterating
If the current letter is a vowel, we split the word into two separate parts and we add them on the other way around, not forgetting to ad the 'ay' suffix.
In the code below I also added to the vowels array the uppercase versions. With some modifications, it can be made to jump over delimiters. The Pig Latin rules were those I found on Wikipedia (although I did not find any rules for words only with consonants, so I put them in the first case).
Cheers!
function has(a, e) {
return a.indexOf(e) > -1;
}
function translateWord(str) {
let vows = ['a', 'e', 'i', 'o', 'u'];
vows = vows.concat(vows.map(v => v.toUpperCase()));
let lastVowelIndex = 0;
let conv = '';
for (let i = 0; i < str.length; ++i) {
let currentChar = str[i];
/* If the first character is a voewl, we just
* add the 'way' suffix to the initial word.
* I applied the same rule for words without
* consonants.
*/
if ((i === 0 && has(vows, currentChar))
|| (i === str.length - 1)) {
conv = str + 'way';
break;
}
/* If the current character is a consonant, we
* just continue until we reach a vowel.
*/
if (!has(vows, currentChar))
continue;
/* At this point, we reached a vowel, so we do the
* appropriate transformations.
*/
let firstPart = str.slice(0, i);
let secondPart = str.slice(i);
conv = secondPart + firstPart + 'ay';
break;
}
return conv;
}
function translateToPigLatin(str) {
let words = str.split(' ');
let converted = words.map(w => translateWord(w));
return converted.join(' ');
}
let s = translateToPigLatin("I have no rythm");
console.log(s);
Why not use a RegExp?
function translatePigLatin(str) {
let res = '';
let regex = /[aeiou]/;
if (!regex.test(str)) {
res = str + 'ay';
} else if (regex.test(str[0])) {
res = str + 'way';
} else {
let x = str.indexOf(regex.exec(str)[0]);
res = str.substr(x) + str.substr(0, x) + 'ay'
}
return res;
}
Related
Example:
aza asssa axxxa rrra -> a!a a!!!a a!!!a rrra
So far I've come up with this solution:
const argument = "aza asssa axxxa rrra";
const amount_of_spaces = [...argument].filter(x => x === " ").length;
let j = 0;
const argument__clone = [...argument];
const space__indices = [];
function do__stuff() {
while (j < amount_of_spaces) {
space__indices.push(argument__clone.indexOf(" ") + j);
argument__clone.splice((argument__clone.indexOf(" ")), 1);
j++;
do__stuff();
}
};
do__stuff();
const words = [];
let word = '';
for (let i = 0; i < argument.length; i++) {
if (!(space__indices.includes(i))) {
word += argument[i];
}
else {
words.push(word);
word = '';
}
}
words.push(word);
let new__word = '';
const new__words = [];
const words__static = [];
for (i of words) {
if (i[0] === 'a' && i[i.length - 1] === 'a') {
for (let j = 1; j < i.length - 1; j++) {
new__word += "!";
}
new__words.push(new__word);
new__word = '';
}
else {
words__static.push(i);
}
}
new__words.map(i => "a" + i + "a");
console.log(new__words);
console.log(words__static);
So one array stores the indices of spaces and the other one stores the words from the given string. We can separate the words because we know when one ends because we have the array with space indices. Then we check for each word whether it starts with 'a' and ends with 'a'. If the requirements are met we change all the letters within the word for "!" (excluding the very first and the very last ones). If the requirements are not met we store the word into the other array.
Eventually we have two arrays that I want to concatenate into one. The problems is if I was given something like this:
aza asssa rrra axxxa
It wouldn't have worked because of the order
Is there any better solution?
A regular expression would be simpler. Match an a after a word boundary, match more non-space characters, and finally match another a followed by a word boundary.
const input = 'aza asssa axxxa rrra';
const output = input.replace(
/(?<=\ba)\S+(?=a\b)/g,
interiorWord => '!'.repeat(interiorWord.length)
);
console.log(output);
For a more manual approach, split the input by spaces so you have an array of words, then for each word, check if it begins and ends with an a - if so, construct a new word by checking the old word's length. Then turn the array back into a single string.
const input = 'aza asssa axxxa rrra';
const words = input.split(' ');
const replacedWords = words.map(word => (
word[0] === 'a' && word[word.length - 1] === 'a' && word.length >= 3
? 'a' + '!'.repeat(word.length - 2) + 'a'
: word
));
const output = replacedWords.join(' ');
console.log(output);
I have been attempting to solve this codewars problem for a while in JavaScript:
"Complete the solution so that the function will break up camel casing, using a space between words. Example:"
"camelCasing" => "camel Casing"
"identifier" => "identifier"
"" => ""
I have it almost all the way, but for some reason my code is selecting the wrong space to add a blank space.
I'm hoping someone can tell me what I am doing wrong.
function solution(string) {
let splitStr = string.split("");
let newStr = string.split("");
let capStr = string.toUpperCase().split("");
for (i = 0; i < splitStr.length; i++) {
if (splitStr[i] === capStr[i]) {
newStr.splice(i, 0, ' ');
}
}
return newStr.join("");
}
console.log('camelCasing: ', solution('camelCasing'));
console.log('camelCasingTest: ', solution('camelCasingTest'));
The first insertion into newStr will be at the correct spot, but after that insertion of the space, the letters that follow it in newStr will be at an increased index. This means that when the next capital is found at i in splitStr (which did not change), the insertion into newStr (which did change) should really be at i+1.
A solution is to make your loop iterate from end to start:
function solution(string) {
let splitStr = string.split("");
let newStr = string.split("");
let capStr = string.toUpperCase().split("");
for (i = splitStr.length - 1; i >= 0; i--) {
if (splitStr[i] === capStr[i]) {
newStr.splice(i, 0, ' ');
}
}
return newStr.join("");
}
console.log('camelCasing: ', solution('camelCasing'));
console.log('camelCasingTest: ', solution('camelCasingTest'));
This kind of problem is however much easier solved with a regular expression:
function solution(string) {
return string.replace(/[A-Z]/g, " $&");
}
console.log('camelCasing: ', solution('camelCasing'));
console.log('camelCasingTest: ', solution('camelCasingTest'));
Explanation of the regular expression:
[A-Z] a capital letter from the Latin alphabet.
$& backreference to the matched letter, used in the replacement.
g global flag so all matches are replaced.
Here could be a solution with a simple loop and some if conditions
const breakCamelCase = (word) => {
let result = "";
// loop on letter
for (let letter of word) {
// if letter is uppercase and not the first letter of the word add a space followed by the letter
if (letter == letter.toUpperCase() && result) {
result += ` ${letter}`;
} else { // else just add the letter
result += letter;
}
}
return result;
}
function solution(string) {
let splitStr = string.split("");
let newStr = "";
splitStr.forEach(e =>{
if(e === e.toUpperCase()) newStr +=" "+e;
else newStr += e;
});
return newStr;
}
console.log(solution('camelCasing'));//success = "camel Casing"
console.log(solution('camelCasingTest'));
new to coding I'm trying to make a function that makes "abbreviations/acronyms" of words, e.g. 'I love you' -> 'ily'.
I've tried rewriting the code in many ways but console.log only shows me the first letter of the first given word.
function makeAbbr(words) {
let abbrev = words[0];
let after = 0;
let i = 0;
for (const letter of words) {
if (letter === '') {
i = words.indexOf('', after);
abbrev += words[i + 1];
}
after++;
}
return abbrev;
}
const words = 'a bc def';
let result = makeAbbr(words);
console.log(result)
Without using arrays. But you really should learn about them.
Start by trimming leading and trailing whitespace.
Add the first character to your acronym.
Loop over the rest of the string and add the current character to the acronym if the previous character was a space (and the current character isn't).
function makeAbbr(words) {
words = words.trim();
const length = words.length;
let acronym = words[0];
for(let i = 1; i < length; i++) {
if(words[i - 1] === ' ' && words[i] !== ' ') {
acronym += words[i];
}
}
return acronym;
}
console.log(makeAbbr('I love you'));
console.log(makeAbbr('I love you'));
console.log(makeAbbr(' I love you '));
And here's the version for GottZ
function w(char) {
char = char.toLocaleLowerCase();
const coll = Intl.Collator('en');
const cmpA = coll.compare(char, 'a');
const cmpZ = coll.compare(char, 'z');
return cmpA >= 0 && cmpZ <= 0;
}
function makeAbbr(words) {
words = words.trim();
const length = words.length;
if(!length) return '';
let acronym = words[0];
for(let i = 1; i < length; i++) {
if(!w(words[i - 1]) && w(words[i])) {
acronym += words[i];
}
}
return acronym;
}
console.log(makeAbbr('I love you'));
console.log(makeAbbr('I love you'));
console.log(makeAbbr(' I love you '));
console.log(makeAbbr(' \tI ... ! love \n\r .you '));
console.log(makeAbbr(' \tI ... ! Löve \n\r .ÿou '));
Since you wanted something using your approach, try this (code is commented)
function makeAbbr(words) {
let abbrev = "";
for (let i = 0; i < words.length - 1; i++) { // Loop through every character except the last one
if (i == 0 && words[i] != " ") { // Add the first character
abbrev += words[i];
} else if (words[i] == " " && words[i + 1] != " ") { // If current character is space and next character isn't
abbrev += words[i + 1];
}
}
return abbrev.toLowerCase();
}
const words = 'a bc def';
let result = makeAbbr(words);
console.log(result)
here is my implementation of your function:
Split the sentence into an array, get the first letter of each word and join them into one string.
const makeAbbr = string => string.split(' ').map(word => word[0]).join('');
console.log(makeAbbr('stack overflow'));
console.log(makeAbbr('i love you'));
`
If you want to use your approach exactly, you had a typo on the line specified. A character can never be "" (an empty string), but a character can be a space " ". Fixing this typo makes your solution work.
function makeAbbr(words) {
let abbrev = words[0];
let after = 0;
let i = 0;
for (const letter of words) {
if (letter === ' ') { // This line here
i = words.indexOf(' ', after);
abbrev += words[i + 1];
}
after++;
}
return abbrev.toLowerCase(); // Also added .toLowerCase()
}
const words = 'a bc def';
let result = makeAbbr(words);
console.log(result)
There are couple of things tripping you up.
let abbrev = words[0]; is just taking the first letter of the word string you passed into the function, and at some point adding something new to it.
for (const letter of words) {...}: for/of statements are used for iterating over arrays, not strings.
Here's a remixed version of your code. It still uses for/of but this time we're creating an array of words from the string and iterating over that instead.
function makeAbbr(str) {
// Initialise `abbrev`
let abbrev = '';
// `split` the string into an array of words
// using a space as the delimiter
const words = str.split(' ');
// Now we can use `for/of` to iterate
// over the array of words
for (const word of words) {
// Now concatenate the lowercase first
// letter of each word to `abbrev`
abbrev += word[0].toLowerCase();
}
return abbrev;
}
console.log(makeAbbr('I love you'));
console.log(makeAbbr('One Two Three Four Five'));
I created a function that given any string will return the string with the first and last letter of each word capitalized. So far it works in some words, not on others, can someone help me figure out why?
function Capitalize(str) {
var spl = str.split(" ");
var words = [];
for (let i = 0; i < spl.length; i++) {
//For every word
for (let j = 0; j < spl[i].length; j++) {
//For every letter in each word
var word = spl[i];
var size = spl[i].length;
var firstLetterCapital = word.replace(word[0], word[0].toUpperCase()); //Creates new array
var LastLetterCapital = firstLetterCapital.replace(
word[size - 1],
word[size - 1].toUpperCase()
);
}
words.push(LastLetterCapital);
}
console.log(words.join(" "));
}
Capitalize("hello there");
It works when I type : Capitalize("my name is john smith"), but not with Capitalize("hello there")
I know it's a complete mess and probably a very bad way to do it, but I started programming a month ago so give me a break :)
#symlink has already explained why it is "HellO ThEre" instead of "Hello TherE". He also has given a solution to explicitly target first and last character of the string. I have accomplished not much different than already posted by members, except for .. "may be" a little more explanation.
You can break the entire problem in these four steps.
Get all the words into an array.
Create a function, that takes each word and targets first and last character, changes it and returns the changed word.
Apply a mapping step using the function created above (in step 2) to the entire array of words (obtained in step 1).
Join the transformed array, obtained in step 3, using a blank space as a separator.
I have written two functions that accomplish this task. I am sorry for long name of functions. It helps me keep track of things in a complex program (especially when I am in a hurry!).
Step 2 function
function Capitalize_FirstAndLast_One_Word(word){
// Split the string in array for easy access/manipulation by indexing
Split_String = word.split("")
// Target the first word
Split_String[0] = Split_String[0].toUpperCase();
// Target the last word
Split_String[Split_String.length - 1] = Split_String[Split_String.length - 1].toUpperCase();
// Join the array into a single word
Joined_Back = Split_String.join("")
return Joined_Back;
}
Step 1, 3 and 4 function
function Capitalize_Entire_String(str){
Regular_Exp = new RegExp(/\w+/g);
//Below is step 1
MatchedArray = str.match(Regular_Exp);
//Below is step 3
ConvertedArray = MatchedArray.map(Capitalize_FirstAndLast_One_Word);
// Below is step 4
ReturnedString = ConvertedArray.join(" ");
console.log(ReturnedString);
return ReturnedString;
}
Now you have everything. You can use the function like below.
Capitalize_Entire_String("hello there");
Capitalize_Entire_String("hello there this is a test");
Hope this helps. I am sorry if this turned out to be a redundant answer for you.
Reason your code don't work is the use of replace(). replace() will always replace the first character found.
There is absolutely no reason to run a nested loop. You can achieve this using a single loop.
function cap(str){
let spl = str.split(' ');
for(let i = 0; i < spl.length; i++){
let temp = spl[i];
temp = temp[0].toUpperCase() + temp.slice(1)
temp = temp.slice(0,-1) + temp[temp.length - 1].toUpperCase();
spl[i] = temp;
}
return spl.join(' ');
}
console.log(cap("a quick brown fox"))
An easier way is to use map() and template strings.
const cap = str => str
.split(' ')
.map(x => (
x.length === 1 ?
x.toUpperCase() :
`${x[0].toUpperCase()}${x.slice(1,-1)}${x[x.length -1].toUpperCase()}`)
)
.join(' ')
console.log(cap("a quick brown fox"))
To simplify the function, you could split the string into an array, map each word to the desired format, and join it together into a string again.
function Capitalize(str){
return str.split(" ").map((word) => word.charAt(0).toUpperCase() +
(word.length > 2 ? word.substring(1, word.length - 1) : "") +
(word.length > 1 ? word.charAt(word.length - 1).toUpperCase() : "")).join(" ");
}
console.log(Capitalize("i want to capitalize first and last letters"));
Congrats on starting out programming...
You can use this to achieve what you want to do
function capitalizeFirstAndLastLetters (str) {
const words = str.split(" "); // Split the string into words
const modified = [];
for (const word of words) {
if (word.length <= 2) {
modified.push(word.toUpperCase()); // If the word less than 3 characters, the whole word is capitalized
continue;
}
var firstCapital = word[0].toUpperCase(); // word[0] gets the first index of the string (I.e. the first letter of the word)
var lastCapital = word.slice(-1).toUpperCase(); // The slice function slices a portion of the word. slice(-1) gets the last letter
var middlePart = word.slice(1, -1); // slice(1, -1) means start slicing from the second index (I.e. 1) and ignore the last index
modified.push(firstCapital + middlePart + lastCapital);
}
return modified.join(" "); // Join each element in the modified array with a space to get the final string with each words first and last letters capitalized
}
capitalizeFirstAndLastLetters("hello there I am a boy"); // "HellO TherE I AM A BoY"
Try this, it worked for hello world because I guess you want the outcome to be HellO TherE right?:
function capitalize(str) {
var spl = str.split(" ");
var words = [];
for (let i = 0; i < spl.length; i++) {
//For every word
let changedWord = "";
for (let j = 0; j < spl[i].length; j++) {
//For every letter in each word
if(j == 0 || j == spl[i].length - 1) {
changedWord += spl[i][j].toUpperCase();
} else {
changedWord += spl[i][j].toLowerCase();
}
}
words.push(changedWord);
console.log(words);
}
console.log(words.join(" "));
}
capitalize("hello there");
ALSO: Make your functions name start with lowercase letter. Thats just how it is. Starting with uppercase letters usually are Classes. Just a quick tip
Maybe this does what you want, don't want to change much from your code:
function Capitalize(str) {
var spl = str.split(" ");
var words = [];
for (let i = 0; i < spl.length; i++) {
var word = spl[i];
var firstCapital = word[0].toUpperCase(); // get first character after capitalizing
var lastCapital = word.slice(-1).toUpperCase(); // get last character after capitalizing
var midOriginal = word.slice(1, -1);
words.push(firstCapital + midOriginal + lastCapital) // concat 3 parts
}
console.log(words.join(" "));
}
Capitalize("hello there");
This expression:
var LastLetterCapital = firstLetterCapital.replace(
word[size - 1],
word[size - 1].toUpperCase()
);
Is replacing the first occurrence of the character "e" in "There" with an uppercase "E".
Explanation
The replace() function first translates the first param: word[size - 1] to the literal character "e", then replaces the first occurrence of that character with the uppercase "E", resulting in the string "ThEre".
Solution
Use a regular expression as your first parameter instead, to ensure that the last character is targeted, regardless of whether or not that same character shows up anywhere else in the word:
var LastLetterCapital = firstLetterCapital.replace(/.$/, word[size - 1].toUpperCase());
function Capitalize(str) {
var spl = str.split(" ");
var words = [];
for (let i = 0; i < spl.length; i++) {
//For every word
var word = spl[i];
var size = spl[i].length;
for (let j = 0; j < size; j++) {
//For every letter in each word
var firstLetterCapital = word.replace(word[0], word[0].toUpperCase()); //Creates new array
var LastLetterCapital = firstLetterCapital.replace(/.$/, word[size - 1].toUpperCase());
}
words.push(LastLetterCapital);
}
console.log(words.join(" "));
}
Capitalize("hello there");
This should do the trick:
function Capitalize(str) {
return str.replace(/(\b\w|\w\b)/g, l => l.toUpperCase())
}
console.log(Capitalize('i want to be capitalized in a rather strange way'))
Explanation:
In the regular expression /(\b\w|\w\b)/g, \b means "word boundary" and \w means "word character", so (\b\w|\w\b) matches a word boundary followed by a word character OR a word character followed by a word boundary (i.e. the first and last character of words).
The matches of this expression are then passed to the inline function l => l.toUpperCase() (which itself is the second argument to replace) that capitalizes the passed letter.
the string type is immutable, so why don't you try to convert the string to an array like y = word.split('') and do y[0] = word.charAt(0).toUpperCase() and then convert back to string with y.join('')
OBJECTIVE
Given a string, translate the string into PigLatin (if the string starts with a vowel, append "way" to end of string - else look for the first vowel and take all preceding letters and place on the end of str, add "ay").
CODE
function translate(str) {
//list vowels
var vowel = ['a', 'e', 'i', 'o', 'u'];
//if first letter = vowel, add 'way' to end of sentence
// else return all letters before first vowel and append to end (with 'ay')
for (var i = 0; i < str.length; i++) {
if (vowel.indexOf(str[0]) > -1) {
return str + 'way';
} else {
return str.substr(i+1) + str.slice(0,i+1) + 'ay';
}
}
}
translate("dresser");
QUESTIONS
The aforementioned code works for cases such as "algorithm" and "desk", but failed with "glove" - leading me to believe the problem is around .substr() or .slice(). Additional investigation believes this is a logic error. Any help is appreciated!
The problem is that your code will always return from the loop during the first iteration. i will never be greater than 0.
What you should do (for starters) is remove the check from inside the loop. Like this:
function translate(str) {
//list vowels
var vowel = ['a', 'e', 'i', 'o', 'u'];
//if first letter = vowel, add 'way' to end of sentence
if (vowel.indexOf(str[0]) > -1) {
return str + 'way';
}
// else return all letters before first vowel and append to end (with 'ay')
for (var i = 0; i < str.length; i++) {
if (vowel.indexOf(str[i]) > -1) {
return str.substr(i) + str.slice(0,i) + 'ay';
}
}
}
This code should do the trick.
You are returning a value without testing if the character is a vowel.
function translate(str) {
//list vowels
var vowel = ['a', 'e', 'i', 'o', 'u'];
//if first letter = vowel, add 'way' to end of sentence
// else return all letters before first vowel and append to end (with 'ay')
for (var i = 0; i < str.length; i++) {
if (vowel.indexOf(str[0]) > -1) {
return str + 'way';
} else if(vowel.indexOf(str[i]) !== -1) {
return str.substr(i) + str.slice(0,i) + 'ay';
}
}
}
Note how I added the if to test if the character is a vowel.
jsfiddle