Say I had the following code:
var str = "abcde";
str.replace("a", "ab")
str.replace("b", "c")
The value of str go from abcde to abbcde to acccde. How would I go about making it so that the two operations happen simultaneously, so that the value of str instead goes from abcde to abccde?
EDIT: I'm talking about any situation similar to this, not just this specific one.
When replace contains these kind of patterns, first do which is indepndent and then other like below.
var str = "abcde";
str.replace("b", "c");
str.replace("a", "ab");
Or else replace both of them using some map:
var str = "abcde";
var mapObj = {
a:"ab",
b:"c"
};
str = str.replace(/a|b/gi, function(matched){
return mapObj[matched];
});
console.log(str);
Output:
abccde
You need to match both a and b with a regular expression, then use a function to distinguish whether it was an a or an b. See documentation for the replace function.
var str = 'abcde'
var newStr = str.replace(/[ab]/g, function (match) {
switch (match) {
case 'a':
return 'ab'
case 'b':
return 'c'
default:
return '???' // or throw error
}
})
console.log(newStr) // -> abccde
If you have a list of strings that you want to replace, you might want to look at how to escape strings to be used in regular expressions, then use the constructor for RegExp to construct the regular expression to be used for the replace function.
var replacements = {'a': 'ab', 'b': 'c'}
var keys = Object.keys(replacements)
// escapeRegExp function from https://stackoverflow.com/a/6969486/8557739
var escapedKeys = keys.map(escapeRegExp)
var re = RegExp(escapedKeys.join('|'), 'g') // re = /a|b/g
// then continue on like before
var str = 'abcde'
var newStr = str.replace(re, function (match) {
for (var key in replacements) {
if (match === key) {
return replacements[key]
}
}
return '???' // or throw error
})
console.log(newStr) // -> abccde
var str = "abcde";
str.replace(/a|b/gbbc);
You can use this regex as well, as it will replace 'a' with 'b' and 'b' with 'bc'.
If you want to apply this regex globally for your String then you can use '/g' as mentioned above else just a / after b.
To chain replacement, use '|' operator as I did between a|b.
I have found a way to do it using arrays.
var str = "abcde";
var str2 = str.split("");
for(var i = 0; i < str2.length; i++){
if(str2[i] === "a"){
str2[i] = "ab"
} else if(str2[i] === "b"){
str2[i] = "c";
}
}
Related
i have a string i need to convert it into a array of object
const str = "addias (brand|type) sneakers(product) for men(o)"
expected output
let output = [
{
key:"addias",
value:["brand","type"]
},
{
key:"sneakers",
value:["product"]
},
{
key:"for men",
value:[]
}
]
code i tried
function gerateSchema(val) {
let split = val.split(" ")
let maps = split.map((i) => {
let obj = i.split("(")
let key = obj[0].replaceAll(/\s/g, "")
let cleanValue = obj[1].replace(/[{()}]/g, "")
let stripedValues = cleanValue.split("|")
return {
key: key,
value: stripedValues,
}
})
return maps
}
let out = gerateSchema(str)
but this breaking when there is some word with space for example for men
how to do split with a regex
One approach would be first do a regex find all to find all key/value combinations in the original string. Then, iterate that result and build out a hashmap using the word keys and the array values.
var str = "addias (brand|type) sneakers(product) for men(o)";
var matches = str.match(/\w+(?: \w+)*\s*\(.*?\)/g, str);
var array = [];
for (var i=0; i < matches.length; ++i) {
var parts = matches[i].split(/\s*(?=\()/);
var map = {};
map["key"] = parts[0];
map["value"] = parts[1].replace(/^\(|\)$/g, "").split(/\|/);
array.push(map);
}
console.log(array);
The first regex matches each key/value string:
\w+ match a word
(?: \w+)* followed by a space, and another word, the quantity zero or more times
\s* optional whitespace
\( (
.*? pipe separated value string
\) )
Then, we split each term on \s*(?=\(), which is the space(s) immediately preceding the (...|...) term. Finally, we split the value string on pipe | to generate the set of values.
An alternative way could be this.
const str = "addias (brand|type) sneakers(product) for men(o)"
const array = str.split(')').filter(i => i.length).map(i => {
const item = i.split('(');
return {
key: item[0].trim(),
value: item[1].split('|')
}
})
console.log(array)
It may be simpler to use the exec method to iterate over the patterns the regex finds.
const str = 'addias(brand|type|size|color) sneakers(pro) for men(o)';
// The regex looks for an initial group of letters,
// then matches the string inside the parentheses
const regex = /([a-z]+)\(([a-z\|]+)\)/g;
let myArray;
const arr = [];
while ((myArray = regex.exec(str)) !== null) {
// Destructure out the key and the delimited string
const [_, key, ...rest] = myArray;
// `split` on the string found in `rest` first element
const values = rest[0].split('|');
// Finally push a new object into the output array
// (removing "o" for whatever reason)
arr.push({
key,
value: values.filter(v => v !== 'o')
});
}
console.log(arr);
With a little help from regex101.com, derived the following regex expressions and the following code.
([^\(]+)\(([^\)]*)\) which breaks down into
([^\(]+) - capture 1 or more chars up to the first ( as group 1
\( - swallow the left parens
([^\)]*) - capture everything up to the next occurrence of ) as group 2
\) - swallow the right parens
and I was starting to [^|]+ - to parse the text of group 2, but it's actually simpler with a simple split statement.
function generateSchema(str) {
const regex = /([^\(]+)\(([^\)]*)\)/mg; // captures the 'word (word)' pattern
let m;
let output = [];
let obj = {};
while ((m = regex.exec(str)) !== null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === regex.lastIndex) {
regex.lastIndex++;
}
m.forEach((match, groupIndex) => {
if (groupIndex === 1) {
obj = {};
obj.key = match.trim();
} else if (groupIndex === 2) {
obj.value = match.split('|').map(i=>i.trim());
output.push(obj);
}
});
}
return output;
}
const str = "addidas (brand | type ) sneakers(product) for men(o)";
console.log(generateSchema(str));
This code returns true for every scenario; it returns true if it's a palindrome and it returns true if it's not a palindrome.
function isPalindrome(string){
string = string.toLowerCase();
var charactersArr = string.split(' ');
var validCharacters = 'abcdefghijklmnopqrstuvwxyz'.split(' ');
var lettersArr = [];
charactersArr.forEach(char => {
if (validCharacters.indexOf(char)> - 1) lettersArr.push(char);
});
return lettersArr.join(' ') === lettersArr.reverse().join(' ');
}
isPalindrome("Taco Cat");
function palindrome(str) {
var re = /[^A-Za-z0-9]/g;
str = str.toLowerCase().replace(re, '');
var len = str.length;
for (var i = 0; i < len/2; i++) {
if (str[i] !== str[len - 1 - i]) {
return false;
}
}
return true;
}
Use this code for checking palindromes . You are complicating your code by passing in var validCharacters = 'abcdefghijklmnopqrstuvwxyz'.split(' ');
You could use re like I have to include all possible combinations including numbers !
It always returns true because lettersArr is always empty. Try to debug your code using debugger or just use console.log for this purpose.
I believe at least this line var charactersArr = string.split(' '); is not doing what is expected: it splits a sentence by space characters into words instead of splitting into separate letters.
It's because lettersArris always empty .... Try this code:
function isPalindrome(string) {
let reversed = string.toLowerCase().split('').reverse().join('');
return reversed === string.toLowerCase()
}
let result1 = isPalindrome("Foo bar")
let result2 = isPalindrome("mom")
console.log(result1, result2)
lettersArr is not what you expect.
You are splitting the input string by spaces, which means you get ['taco', 'cat'] and not ['t', 'a', 'c', 'o', 'c', 'a', 't'].
Then when this line runs:
if (validCharacters.indexOf(char)> - 1) lettersArr.push(char);
char is 'taco' which isn't found in validCharacters, so nothing gets pushed into lettersArr.
And since lettersArr is empty:
lettersArr.join(' ') === lettersArr.reverse().join(' ');
Becomes:
[].join(' ') === [].reverse().join(' ')
Which, of course, it always true.
To fix it you simply want to split the string by an empty string, which gives you array of single character strings.
function isPalindrome(string){
string = string.toLowerCase();
var charactersArr = string.split('');
var validCharacters = 'abcdefghijklmnopqrstuvwxyz'.split('');
var lettersArr = [];
charactersArr.forEach(char => {
if (validCharacters.indexOf(char)> - 1) lettersArr.push(char);
});
return lettersArr.join(' ') === lettersArr.reverse().join(' ');
}
console.log("Taco Cat", isPalindrome("Taco Cat"));
console.log("abc", isPalindrome("abc"));
I want to determine if string has at least 2 same elements from the array
const array = ["!", "?"];
const string1 = "!hello"; // should return false
const string2 = "!hello?"; // should return false
const string3 = "!hello!"; // should return true
const string4 = "hello ??"; // should return true
const string5 = "hello ?test? foo"; // should return true
const string6 = "hello ?test ?? foo"; // should return true
I'm not sure what is gonna be better: a regex or a function? Any would be fine.
I tried this:
const array = ["!", "?"];
const string = "test!";
array.every(ar => !string.includes(ar));
But it only detects if there at least 1 elements from array, not 2.
You can use Array#some and String#split to do it:
const check=(array,string)=>array.some(char=>(string.split(char).length-1)>=2)
const array = ["!", "?"];
console.log(check(array,"!hello"))
console.log(check(array,"!hello?"))
console.log(check(array,"!hello!"))
console.log(check(array,"hello ??"))
console.log(check(array,"hello ?test? foo"))
console.log(check(array, "hello ?test ?? foo"))
How does it work?
Let's split up (I mean to split() up)!
const check=(array,string)=>
array.some(char=>
(
string.split(char)
.length-1
)>=2
)
First, use Array#some, which tests that at least one element of the array should pass (i.e. either ? or !)
Split up the string by char, and count how many parts do we have
If we have n parts, it means that we have n-1 places where the char matches. (e.g. 2 | splits a string into 3 parts: a|b|c)
Finally, test whether we have 2 or more delimiters
Another way is to use a pattern with a capturing group and a dynamically created character class for [!?] and a backreference \1 to what is captured in group 1 to make sure there are 2 of the same characters present.
([!?]).*\1
Regex demo
For example
const array = ["!", "?"];
const regex = new RegExp("([" + array.join(("")) + "]).*\\1");
[
"!hello",
"!hello?",
"!hello!",
"hello ??",
"hello ?test? foo",
"hello ?test ?? foo"
].forEach(str => console.log(str + ": " + regex.test(str)));
You can use string split and array length like:
const array = ["!", "?"];
const string6 = "hello ?test ?? foo";
var len1 = string6.split(array[0]).length;
var len2 = string6.split(array[1]).length;
if (len>2)||(len2>2)
return true;
EDIT: Using for loop
for (let i=0;i<array.length;i++){
var len = string6.split(array[i]).length;
if (len>2)
return true;
}
return false;
You can follow a very simple solution like below. Split the string using the character in array. check the left of the split operation. If the length is minimum 2, then return true, else false.
Here is a sample jsFiddle: https://jsfiddle.net/sagarag05/qk8f2Lz7/
const array = ["!", "?"];
var str = "How are you!! doing !today?";
function isFound(arr, str){
var isPresent = false;
for(var i=0; i < arr.length; i++){
var res = str.split(arr[i]);
if(res.length-1 >= 2){
isPresent = true;
break;
}
}
return isPresent;
}
isFound(array, str);
Create a function which can be handy for n number of occurrences to find
const arrayData = ["!", "?"];
const strData = "test!";
function checkElements(arr, str, occNum) {
var ctr = 0;
arr.forEach(function (elem) { if(str.includes(elem)) ctr++});
return ctr >= occNum
}
checkElements(arrayData, strData, 2)
Use loop over array and count occurrence then check if occurrence is greater than 1.
function has2(string1, array)
{
for(let i=0;i<array.length;i++)
{
if (string1.split('').reduce(function(n, val) {
return n + (val === array[i]);
}, 0) > 1)
{
return true;
}
}
return false;
}
console.log(has2("!hello!", ["!", "?"])); // true
console.log(has2("!hello?", ["!", "?"])); // false
Here is a regex trick approach. We can try removing all characters from the input which are not part of the character class of characters to find. Then, assert that there are at least two distinct characters remaining in the input.
var input = "!hello?";
input = input.replace(/[^!?]+/g, "");
if (/(.).*(?!\1)./.test(input)) {
console.log("MATCH");
}
else {
console.log("NO MATCH");
}
The logic here is fairly straightforward. Using the input !hello? as an example, we first remove all non marker characters, leaving us with !?. Then, we use a regex to assert that there are at least two distinct characters remaining. This is true for this input, so we print MATCH.
Edit:
To build the regex alternation from your input array use join:
const array = ["!", "?"];
var regex = "[^" + array.join("") + "]+";
There is a much simpler solution for this:
var a = ["!", "?"], s = "!hello!";
a.some(v=>s.split(v).length>2) // (returns true if multiples are found)
We can turn it into a function to test:
const a = ["!", "?"];
function Test(s) { return a.some(v => s.split(v).length > 2) }
const string1 = "!hello"; // should return false
const string2 = "!hello?"; // should return false
const string3 = "!hello!"; // should return true
const string4 = "hello ??"; // should return true
const string5 = "hello ?test? foo"; // should return true
const string6 = "hello ?test ?? foo"; // should return true
console.log(Test(string1), Test(string2), Test(string3), Test(string4),
Test(string5), Test(string6));
> false false true true true true
Note: My code changed a few times and in the end was close to the accepted answer and I didn't realize. That said, you don't need to subtract anything, so that part is unnecessary.
function checkDups(arr, str) {
var ctr = [];
for (var i = 0; i < arr.length; i++) {
var pos = str.indexOf(arr[i]);
var count = 0;
ctr[i] = 0;
while (pos > -1) {
++count;
pos = str.indexOf(arr[i], ++pos);
}
if (count >= 2) {
return true
}
}
return false
}
console.log(checkDups(["!", "?"], "!hello"))
console.log(checkDups(["!", "?"], "!hello?"))
console.log(checkDups(["!", "?"], "!hello!"))
console.log(checkDups(["!", "?"], "hello ??"))
console.log(checkDups(["!", "?"], "hello ?test? foo"))
console.log(checkDups(["!", "?"], "hello ?test ?? foo"))
I am trying to put all the words that have the letter e in a separate array yet I can not figure out how to input a variable into the Regular Expression.
I have already tried plugging a variable into a metacharacter of regex.
var inputletter = "e"
startlist = ["jambee", "dangen", "oragna", "sabotta"];
filter1 = [];
var regex = new RegExp(startlist, "g");
for (var i = 0; i < startlist.length; i++) {
if(regex.test(regex, "regex") == true) {
filter1.push(startlist[i])
}
};
console.log(filter1);
You can use array filter function and also use includes to check if the word contains the character
var inputletter = "e"
startlist = ["jambee", "dangen", "oragna", "sabotta"];
function filter1(arr, char) {
return arr.filter(function(item) {
return item.includes(char)
})
}
console.log(filter1(startlist, inputletter));
you are using test wrong:
let regex = new RegExp("e");
...
if(regex.test(startlist[i])) {...
If you don't mind moving away from using a regex, you can use Javascript's array.prototype.filter(), string.prototype.toLowerCase() and the string.prototype.includes() methods to create an array where each element has at least one 'e'
let startlist = ["jambee", "dangen", "oragna", "sabotta"];
let result = startlist.filter((element) => element.toLowerCase().includes('e'));
console.log(result);
If you want to keep your existing code you simply need to test the letter (the regex consisting of just that letter) against each element in the array (startlist[i]).
const startlist = ['jambee', 'dangen', 'oragna', 'sabotta'];
const filter1 = [];
const regex = /e/;
for (var i = 0; i < startlist.length; i++) {
const word = startlist[i];
if (regex.test(word)) filter1.push(word);
};
console.log(filter1);
Alternatively you can use a slightly more functional method using the array filter method, and the string includes method
const startlist = ["jambee", "dangen", "oragna", "sabotta"];
const filtered = startlist.filter(word => {
return word.includes('e');
});
console.log(filtered);
Take a look at the code bellow, it's pretty self-explanatory. How do I modify the 'replaceAt' function to get the desired results?
String.prototype.replaceAt = function (at) {
return this.substring(0, at) + this.substring(at+1, this.length);
}
var str = "webmaster";
var x = str.replaceAt(2);
console.log(x); // should return "b"
console.log(str); // should return "wemaster"
You can't, strings are immutable.
One other approach would be to return an object or array containing the replaced character, and the new string. Then assign the values to the variables 'x' and 'str', respectively:
String.prototype.replaceAt = function (at) {
return {
x: this.substring(at+1, at),
str: this.substring(0, at) + this.substring(at+1, this.length)
}
};
var str = "webmaster";
var result = str.replaceAt(2);
var x = result.x;
str = result.str;
console.log(x);
console.log(str);
However, utilizing the ES6 feature 'destructuring', you can in fact bring it down to a oneliner:
String.prototype.replaceAt = function (at) {
return [
this.substring(at+1, at),
this.substring(0, at) + this.substring(at+1, this.length)
]
};
var str = "webmaster";
[x, str] = str.replaceAt(2);
console.log(x);
console.log(str);