Replace words in var string by elements of array in JS - javascript

My code automatically search the string for color names and adds random number suffixes and stores them as elements in an array.
What I want is to create a new string with the new modified elements of my array.
Problem comes when string has multiple occurrences of the same color name.
What I need is to replace these occurrences with the different elements of my exported array one by one.
(I don't want to split string in Array, replace the same elements with the other array in a brand new one and then join it to a string. I need to modify the original string)
Example:
String changes through user input so if i have:
str = ' little red fox is blue and red cat is blue';
then my code finds all color names and produces a new array like that:
array = [ 'red2354' , 'blue7856' , 'red324', 'blue23467'] ;
(my code adds RANDOM suffixes at the end of every color element but the order of my array is the same as the string's occurrences)
Desired Output:
str = ' little red2354 fox is blue7856 and red324 cat is blue23467 ';
I tried so far:
var str = ' little red fox is blue and red cat is blue ';
//I have split string to Array:
ar1 = [ "little","red","fox","is","blue","and","red","cat","is","blue"];
//var dup = matchmine(ar1) find all color duplicates :
var dup = ["red","blue","red","blue"];
//I've sorted all duplicates to appear only once for option B:
var dup2 = ["red","blue"];
//var res = modify(str) takes all color names and adds random suffixes:
var res= ["redA" , "blueA" , "redB", "blueB" ] ;
//I have also create a new array with all strings in case I needed to match lengths:
var final = [ "little","redA","fox","is","blueA","and","redB","cat","is","blueB"];
var i = ar1.length-1;
for ( i ; i >= 0; i--) {
var finalAr = str.replace(ar1[i],final[i]);
str = finalAr;}
alert(finalAr);
Problem is that loop goes and 1st time replace one by one all elements. So far so good but in the following loops replace the first again.
loops result:
str = 'little redAB fox is blueAB and red cat is blue '
Desired output:
str = 'little redA fox is blueA and redB cat is blueB '

Some of your logic remains hidden in your question, like on what grounds you determine which word should get a suffix, or how that suffix is determined.
So my answer cannot be complete. I will assume all words that are duplicate (including "is"). If you already know how to isolate the words that should be taken into consideration, you can just inject your word-selection-logic where I have looked for duplicates.
For the suffix determination, I provide a very simple function which produces a unique number at each call (sequentially). Again, if you have a more appropriate logic to produce those suffixes, you can inject your code there.
I suggest that you create a regular expression from the words that you have identified, and then call replace on the string with that regular expression and use the callback argument to add the dynamic suffix.
Code:
function markDupes(str, getUniqueNum) {
// 1. Get all words that are duplicate (replace with your own logic)
let dupes = str.match(/\S+/g).reduce(({words, dupes}, word) => ({
dupes: words.has(word) ? dupes.concat(word) : dupes,
words: words.add(word)
}), {words: new Set, dupes: []} ).dupes;
// Turn those words into a regular expression. Escape special characters:
dupes = dupes.map(word => word.replace(/[\/\\^$*+?.()|[\]{}]/g, '\\$&'))
.join("|");
let regex = new RegExp(dupes, "g");
// Make the replacement of duplicate words and call the callback function:
return str.replace(regex, word => word + getUniqueNum());
}
// Example has two inputs:
// 1. A function that determines the suffix:
// Every call should return a different value
var getUniqueNum = ((i = 1) => {
// ... here we choose to just return an incremental number
// You may implement some other (random?) logic here
return () => i++;
})();
// 2. The input string
let str = 'little red fox is blue and red cat is blue ';
// The call:
console.log(markDupes(str, getUniqueNum));

Make an object that works as a map for your replacers:
const replacers = {
red: 'redA',
blue: 'blueB'
}
Then split your string into an array of words and map over it, replacing as you go:
const inputStr = 'this is my red string blue words'
const stringArr = inputStr.split(' ')
const result = stringArr.map(word=> replacers[word]?replacers[word]:word). join(' ')

Related

Swapping first letters in name and altering capitalization using JavaScript? (looking to optimize solution)

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}`)

Randomize words in a sentence / string with Javascript and list all the variations

i've searched a lot but havent found exactly what i am trying to do. But here goes:
I want to input a sentence / string in javascript and output all randomized variations of that sentence.
Example
input: 'my test sentence 123'
output: 'test my sentence 123', 'my sentence 123 test', '123 sentence my test', and so on, and stop when theres no variations left.
I've split the sentence into words in an array, but im a bit stuck on how to proceed to randomize the words and join them to new sentences in a list or new array.
code so far:
let str = "my test sentence 123";
let words = str.split(" ");
for (let i = 0; i < words.length - 1; i++) {
words[i] += " ";
}
A bit stuck on how to proceed. My thought process is: I have the words variable / array, but i need to randomize each word, output new strings but also check the existing ones so i don't duplicate any of them.
Thanks for all help i can get to learn more :)
Check this code
var phrase = "my test sentence 123";
var words = phrase.toLowerCase().match(/\w+/g);
var wordsCopy = phrase.toLowerCase().match(/\w+/g);
// First of all I loop each word
words.forEach(function(word, index){
// Random word going to contain my randomized word
var randomWord = word;
// Copy the entire phrase
var wordsMissing = wordsCopy.slice();
// Remove the current word
wordsMissing.splice(wordsCopy.indexOf(word), 1);
// Loop tru my missing words
for (var i = 0; i < wordsMissing.length; i++) {
// Set my random word with the rest of the words
randomWord += " " + wordsMissing.join(" ");
// get the first word and send to the final of my original phrase
var firstWord = wordsMissing.splice(0,1)[0];
wordsMissing.push(firstWord);
// Log my random word
console.log(randomWord);
// Reset random word to the initial word
randomWord = word;
}
});
As you are on Javascript, using .join(' ') will be easier to create a string from an array.
Then, there is a lot of solutions to achieve what you want to do, the easier way would be a foreach on foreach, where you simply test if the string you created already exists in the array.
It would be the easy way, but the more you put items, the more you will need power, so use this solution wisely.
Something like this can work :
var stringToSplit = 'I want to split this'
var stringSplitted = stringToSplit.split(' ')
var arrayOfNewStrings = []
stringSplitted.forEach(word => {
var arrayOfString = []
arrayOfString.push(word)
stringSplitted.forEach(otherWord => {
if(word !== otherWord)
arrayOfString.push(otherWord)
})
arrayOfNewStrings.push(arrayOfString)
});
console.log(arrayOfNewStrings)
You then need to add a layer of for/foreach to make it for every words (this will work only for the first one), and to test if the array already exists in ArrayOfNewStrings to prevent duplication.

Show array as scentence except first item

How can I output an array as a scentence except the (1) item? Let's say the content of the array is: ["!report","Jay","This","is","the","reason"];
I tried this to output the items after the (1): (args.slice(1));however the output now is: "This,is,the,reason", how could I make it output as a normal scentence?
If you don't want to use built in methods, you can append each word
in the array starting at index 1 (second item).
// List of words
var words = ["!report","Jay","This","is","the","reason"];
// Empty string
var sentence = "";
// Loop through array starting at index 1 (second item)
for (let i = 1; i < words.length; i++) {
// Keep appending the words to sentence string
sentence = sentence + words[i] + " ";
}
// Print the sentence as a whole
console.log(sentence);
Or using built in functions:
// Array of strings
var array = ["!report","Jay","This","is","the","reason"];
// Cut off the first element, words is still an array though
var words = array.slice(1)
// Join each element into a string with spaces in between
var sentence = words.join(" ")
// Print as full sentence
console.log(sentence)
Output:
"Jay This is the reason"
You could slice from the second element and join the array.
console.log(["!report","Jay","This","is","the","reason"].slice(2).join(' '));
.slice() returns a new array, so when you access it as a whole, you often see a comma separated list of the array values.
But, .slice() along with .join() does the trick. .join() allows you to "join" all the array values as a single string. If you pass an argument to .join(), that argument will be used as a separator.
You can then just concatenate a period (.) to the end of the string.
console.log(["!report","Jay","This","is","the","reason"].slice(1).join(" ") + ".");
The output you desire is not very clear (do you want to remove only the first item or also the second). However the methods are the same:
you can use destructuring assignment syntax if you're es6 compliant
const arr = [a,b,...c] = ["!report","Jay","This","is","the","reason"];
let sentence = c.join(" ");
// or
let sentence2 = c.toString().replace(/,/g," ");
console.log (sentence," - ",sentence2);
or simply replace with regex and a correct pattern
const arr = ["!report","Jay","This","is","the","reason"];
let sentence = arr.toString().replace(/^[A-z! ]+?,[A-z ]+?,/,"").replace(/,/g," ");
// or
let sentence2 = arr.toString().replace(/^[A-z! ]+?,/,"").replace(/,/g," ");
console.log (sentence," - ",sentence2);
Here it is, check fiddle comments for code explanation.
var a = ["!report","Jay","This","is","the","reason"];
//removes first element from array and implodes array with spaces
var sentence = a.slice(1).join(" ");
console.log(sentence);

Dynamically match multiple words in a string to another one using regExp

We all know that regExp can match two strings using a common word in both strings as criterion for the match. This code will match "I like apples" to "apples" because they both have "apples" in common.
var str1 = "apples";
var test1 = "I like apples";
var reg1 = new RegExp(str1, "i");
if (test1.match(reg1)) {
console.log(str1 + " is matched");
}
But what if instead of matching the strings using a single common word (or a common part of the strings), I need to match the two strings using multiple common words which may be separated by other words ? Let me show you an example :
test2 = "I like juicy red fruits" should match str2 = "juicy fruits" because test2 contains all of str2 second key words (see object bellow), even though it has other words inbetween.
Tricky part is that I can't know exaclty what one the strings will be, so I have to match them dynamically. The string I don't know is the value of a user input field, and there are many possibilities. This value is to be matched to the strings stored in this object :
var str2 = {
"red apples": "fruits",
"juicy fruits": "price : $10"
};
So whatever the user types in the input field, it must be a match if and only if it contains all the words of one of the object properties. So in this example, "juicy red and ripe fruits" should match the second object property, because it contains all of its keywords.
Edit : My goal is to output the value associated to the strings I'm matching. In my example if the first key is matched, 'fruits' should be output. If 'juicy fruits' is matched, it should output 'price : $10'. Getting the strings associated to the object keys is the reason why the user has to search for them using the input.
Is it possible to do this with regExp using pure javascript ?
Here is what I (poorly) tried to do : https://jsfiddle.net/Hal_9100/fzhr0t9q/1/
For the situation you're describing, you don't even need regular expressions. If you split the search string on spaces; you can check every one of the words to match is contained within the array of search words.
function matchesAllWords(searchWords, inputString) {
var wordsToMatch = inputString.toLowerCase().split(' ');
return wordsToMatch.every(
word => searchWords.indexOf(word) >= 0);
}
In the snippet below, typing in the input causes a recalculation of the searchWords. The matching li elements are then given the .match class to highlight them.
function updateClasses(e) {
var searchWords = e.target.value.toLowerCase().split(' ');
listItems.forEach(listItem => listItem.classList.remove('match'));
listItems.filter(
listItem =>
matchesAllWords(searchWords, listItem.innerText))
.forEach(
matchingListItem =>
matchingListItem.classList.add('match'));
}
function matchesAllWords(searchWords, inputString) {
var wordsToMatch = inputString.toLowerCase().split(' ');
return wordsToMatch.every(
word => searchWords.indexOf(word) >= 0);
}
function searchProperties(e) {
var searchWords = e.target.value.toLowerCase().split(' ');
for (var property in propertiesToSearch) {
if (matchesAllWords(searchWords, property)) {
console.log(property, propertiesToSearch[property]);
}
}
}
var propertiesToSearch = {
"red apples": 1,
"juicy fruit": 2
};
listItems = [].slice.call(
document.getElementById('matches').querySelectorAll('li')
);
document.getElementById('search').addEventListener('keyup', updateClasses);
document.getElementById('search').addEventListener('keyup', searchProperties);
.match {
color: green;
}
<label for="search">
Search:
</label>
<input type="text" name="search" id="search" />
<ul id="matches">
<li>red apples</li>
<li>juicy fruits</li>
</ul>
Update To use this kind of implementation to search for a property, use a for .. in loop like below. Again, see the snippet for this working in context.
function searchProperties(e) {
var searchWords = e.target.value.toLowerCase().split(' ');
for (var property in propertiesToSearch) {
if (matchesAllWords(searchWords, property)) {
console.log(property, propertiesToSearch[property]);
}
}
}
var propertiesToSearch = {
"red apples": 1,
"juicy fruit": 2
};
I think you might benefit from transforming your data structure from an object literal to an array like so:
const wordGroupings = [
'red apples',
'juicy fruits'
];
I wrote a processString function that accepts a string and some word-groupings as inputs and returns a filtered list of the word-groupings from where each word in the word-grouping occurs in the input string.
In other words let's imagine the test string is:
const testString = 'I like big, frozen whales.';
And let's further imagine that your wordGroupings array looked something like this:
const wordGroupings = [
'whales frozen',
'big frozen whales toucan',
'big frozen',
'sweaty dance club',
'frozen whales big'
]
The output of calling processString(wordGroupings, testString) would be:
[
'whales frozen',
'big frozen',
'frozen whales big'
]
If this is what you're looking for, here is the implementation of processString(..):
function processString(wordGroupings, testString) {
var regexes = wordGroupings.map(words => ({
origString: words,
regex: new RegExp(words.replace(/\s+/g, '|'), 'g'),
expCount: words.split(/\s+/g).length
})
);
filtered = regexes.filter(({regex, expCount}) =>
(testString.match(regex) || []).length === expCount
);
return filtered.map(dataObj => dataObj.origString);
}
Hope this helps!

Remove (n)th space from string in JavaScript

I am trying to remove some spaces from a few dynamically generated strings. Which space I remove depends on the length of the string. The strings change all the time so in order to know how many spaces there are, I iterate over the string and increment a variable every time the iteration encounters a space. I can already remove all of a specific type of character with str.replace(' ',''); where 'str' is the name of my string, but I only need to remove a specific occurrence of a space, not all the spaces. So let's say my string is
var str = "Hello, this is a test.";
How can I remove ONLY the space after the word "is"? (Assuming that the next string will be different so I can't just write str.replace('is ','is'); because the word "is" might not be in the next string).
I checked documentation on .replace, but there are no other parameters that it accepts so I can't tell it just to replace the nth instance of a space.
If you want to go by indexes of the spaces:
var str = 'Hello, this is a test.';
function replace(str, indexes){
return str.split(' ').reduce(function(prev, curr, i){
var separator = ~indexes.indexOf(i) ? '' : ' ';
return prev + separator + curr;
});
}
console.log(replace(str, [2,3]));
http://jsfiddle.net/96Lvpcew/1/
As it is easy for you to get the index of the space (as you are iterating over the string) , you can create a new string without the space by doing:
str = str.substr(0, index)+ str.substr(index);
where index is the index of the space you want to remove.
I came up with this for unknown indices
function removeNthSpace(str, n) {
var spacelessArray = str.split(' ');
return spacelessArray
.slice(0, n - 1) // left prefix part may be '', saves spaces
.concat([spacelessArray.slice(n - 1, n + 1).join('')]) // middle part: the one without the space
.concat(spacelessArray.slice(n + 1)).join(' '); // right part, saves spaces
}
Do you know which space you want to remove because of word count or chars count?
If char count, you can Rafaels Cardoso's answer,
If word count you can split them with space and join however you want:
var wordArray = str.split(" ");
var newStr = "";
wordIndex = 3; // or whatever you want
for (i; i<wordArray.length; i++) {
newStr+=wordArray[i];
if (i!=wordIndex) {
newStr+=' ';
}
}
I think your best bet is to split the string into an array based on placement of spaces in the string, splice off the space you don't want, and rejoin the array into a string.
Check this out:
var x = "Hello, this is a test.";
var n = 3; // we want to remove the third space
var arr = x.split(/([ ])/); // copy to an array based on space placement
// arr: ["Hello,"," ","this"," ","is"," ","a"," ","test."]
arr.splice(n*2-1,1); // Remove the third space
x = arr.join("");
alert(x); // "Hello, this isa test."
Further Notes
The first thing to note is that str.replace(' ',''); will actually only replace the first instance of a space character. String.replace() also accepts a regular expression as the first parameter, which you'll want to use for more complex replacements.
To actually replace all spaces in the string, you could do str.replace(/ /g,""); and to replace all whitespace (including spaces, tabs, and newlines), you could do str.replace(/\s/g,"");
To fiddle around with different regular expressions and see what they mean, I recommend using http://www.regexr.com
A lot of the functions on the JavaScript String object that seem to take strings as parameters can also take regular expressions, including .split() and .search().

Categories