this.personRegex = (input) => {
return new RegExp(persons.map((person) => {
return person.fullname;
}).join("|"), "gi");
}
the above give me :
/lwe|alvin/gi;
How do I get the below:
/\b(?:lwe|alvin)\b/gi;
personRegex = (persons) => {
return new RegExp("\\b(?:"+persons.map((person, i) => {
return person.fullname;
}).join("|") + ")\\b", "gi");
}
console.log(personRegex([{
fullname: "lwe"
}, {
fullname: "alvin"
}]));
You can simply do string concatenation:
var personAlternatives = persons.map((person) => { return person.fullname; }).join("|")
this.personRegex = (input) => {
return new RegExp('\\b(?:' + personAlternatives + ')\\b', "gi");
}
This should give you the least overhead:
function buildRegex(array){
var reg;
var mapResult = array.map((item) => {
return item.attr;
}).join("|");
return new RegExp("\\b(?:"+mapResult+")\\b", "gi");
}
console.log(buildRegex([{attr:"a"},{attr:"b"}]));
You can use template strings, with String.raw to avoid worrying about double backslashes:
personRegex = input =>
new RegExp(
String.raw`\b(?:${input.map(person => person.fullname).join("|")})\b`,
"gi");
console.log(personRegex([{fullname: 'Bob'}, {fullname: 'Sally'}]));
In the real world, you would want to escape any possible special regexp characters in the input. For more information on doing that, see this question.
Related
I need to replace all characters of an incoming string with the corresponding ones from an object, how can I do this using an array?
function handleCyrillic(str) {
const obj = {
й: "\\'e9",
ц: "\\'f6",
};
let res = "";
const arr = Object.keys(obj);
arr.forEach((item) => {
const regex = new RegExp(item, "gi");
res += str.replace(regex, function (s) {
return s
.split("")
.map((n) => (n = obj[n]))
.join("");
});
});
return res;
}
console.log(handleCyrillic("цй йй!!"));
I get in the console ц\'e9 \'e9\'e9!!\'f6й йй!!
I expected \'f6\'e9 \'e9\'e9!!
The problem is that res variable is being overwritten each time a character is replaced instead of appending the replacement to the result. This is updated and a bit refactored version:
function handleCyrillic(str) {
const obj = {
й: "\\'e9",
ц: "\\'f6",
};
let res = str;
Object.keys(obj).forEach((key) => {
const regex = new RegExp(key, "gi");
res = res.replace(regex, obj[key]);
});
return res;
}
You just need to join your obj keys and surround with square brackets for the or condition and in the replace method callback replaces the match string with the corresponding replacement in the obj.
function handleCyrillic(str) {
const obj = {
й: "\\'e9",
ц: "\\'f6",
};
const arr = Object.keys(obj);
const regex = new RegExp(`[${arr.join()}]`, "gi");
return str.replace(regex, function(s) {
return obj[s]
});
}
console.log(handleCyrillic("цй йй!!"));
In your code you are replacing on the str which is parameter which never going to be change and you are concate that into the res which is function return variable that's why you are not getting desired output
function handleCyrillic(str) {
const obj = {
й: "\\'e9",
ц: "\\'f6",
};
let res = str;
const arr = Object.keys(obj);
arr.forEach((item) => {
const regex = new RegExp(item, "gi");
res = res.replace(regex,obj[item]);
});
return res;
}
console.log(handleCyrillic("цй йй!!"));
Try this. At first split the string. If a character exists as a key in the obj, map() returns the obj value, if not it returns the current character. In the end join the string.
function handleCyrillic(str) {
const obj = {
й: "\\'e9",
ц: "\\'f6",
};
return str.split('').map(char => obj[char] || char).join('');
}
console.log(handleCyrillic("цй йй!!"));
There is no need for a regular expression here. You can use Array.from with its callback:
const obj = {
й: "\\'e9",
ц: "\\'f6",
};
const handleCyrillic = str => Array.from(str, ch => obj[ch] ?? ch).join("");
console.log(handleCyrillic("цй йй!!"));
The ?? operator deals with cases where there is no mapping for a character. This still allows a mapping to the empty string to be included in obj, which means you want to remove a character.
There's no need for this conversion table in the first place. Basic Unicode Cyrillic is continuous in range 410...44f and Win-1251 is c0..ff, so you can just do some codepoint arithmetics to convert between both:
function handleCyrillic(str) {
let res = ''
for (let chr of str) {
let cp = chr.codePointAt(0)
if (0x410 <= cp && cp <= 0x44f)
res += "\\'" + (cp - 0x410 + 0xc0).toString(16)
else
res += chr
}
return res;
}
console.log(handleCyrillic("цй йй!!"));
These toTitleCase functions rougly do the same thing.
But I'm curious to know why v1_toTitleCase would be faster than v5_toTitleCase?
And why v6_toTitleCase is faster than v3_toTitleCase? Since this is practically the same thing but v3_toTitleCase is specific to spaces.
I'd like to get the same performance as v2_toTitleCase but don't want to uppercase inputs like (hello => (Hello.
const input = "hello world! how are you today? Upper case Everything.";
const v1_toTitleCase = (str) => {
if (!str) {
return str;
}
const parts = str.toLowerCase()
.split(' ');
return parts.map(part => {
if (!part?.length) {
return part;
}
const firstLetter = part[0].toUpperCase();
const remainingLetters = part.substr(1, part.length);
return firstLetter + remainingLetters;
})
.join(' ');
}
const RegexFirstLetterOfWords = /(?:^| )(\S)/g;
const v2_toTitleCase = (str) => {
return str.replace(/\b[a-z]/g, letter => letter.toUpperCase());
};
const v3_toTitleCase = (str) => {
return str.replace(/(?:^| )(\S)/g, letter => letter.toUpperCase());
};
const v4_toTitleCase = (str) => {
return str.replace(RegexFirstLetterOfWords, letter => letter.toUpperCase());
};
const v5_toTitleCase = (str) => {
return str.replace(/(?:^| )(\w)/g, letter => letter.toUpperCase());
};
// underscore.string implementation.
const v6_toTitleCase = (str) => {
return str.replace(/(?:^|\s|-)\S/g, letter => letter.toUpperCase());
};
Here's a performance runner.
Thoughts?
Is there a faster regex that I'm unaware of like \b but for splitting text by whitespace?
I have the following snippet from this post, this code replaces the token $ENV[accountsDomain] in a string with the key from item object accountsDomain: 'www.yahoo.com' and similarly for accountsUrl
how can I run replace conditionally, replace the string only if item[g1] exists, as these keys are optional
const item = {
accountsUrl: 'www.google.com',
accountsDomain: 'www.yahoo.com'
}
const regex = /\$ENV\[(\w+)]/
let s = "foo$ENV[accountsDomain]bar";
s = s.replace(regex, (m, g1) => item[g1] || m);
console.log(s);
You cannot do that in replace, you have to do it outside.
const item = {
accountsUrl: 'www.google.com',
accountsDomain: 'www.yahoo.com'
}
function replaceItem(item, key) {
const regex = /\$ENV\[(\w+)]/
let s = `foo$ENV[${key}]bar`;
let [, match] = s.match(regex);
return item[match] && s.replace(regex, (m, g1) => item[g1]);
}
console.log('result with existing key:', replaceItem(item, 'accountsDomain'))
console.log('result with un-existing key:', replaceItem(item, 'accDomain'))
I'm trying to write a function that will capitalize the first letter of the first and last name only... any ideas on how to approach this?
const namesHardest = ['emIly sMith', 'angeliNA Jolie', 'braD piTt'];
function capitalizeNames(peopleArray) {
return peopleArray.toString().toLowerCase().split('').map(function(word) {
return (word.charAt(0).toUpperCase() + word.slice(1));
}).join(' ').split();
}
// set the resulting array to this variabble
const capitalizedNames = capitalizeNames(namesHardest);
capitalizedNames;
One issue is using array.toString - that results in a string like
'emIly sMith angeliNA Jolie braD piTt'
so, you've lost your array elements
You need to work on each element individually, by using array.map
function capitalizeNames(peopleArray) {
return peopleArray.map(function(name) {
/* do something with each name *
})
}
Your other issue is that split('') splits a string into characters - but you want to split it on spaces ... i.e. split(' ')
So now, we have
function capitalizeNames(peopleArray) {
return peopleArray.map(function(name) {
return name.split(' ').map(function(word) {
/* do something with each part of name *
});
});
}
so, now, how to capitalise a string - your code works, but I prefer
word[0].toUpperCase() + word.slice(1).toLowerCase();
put it together and you get
function capitalizeNames(peopleArray) {
return peopleArray.map(function(name) {
return name.split(' ').map(function(word) {
return word[0].toUpperCase() + word.slice(1).toLowerCase();
});
});
}
or, in ES2015+, using arrow functions (since your code uses const, why not use all of ES2015+)
const namesHardest = ['emIly sMith', 'angeliNA Jolie', 'braD piTt'];
const capitalizeNames = peopleArray => peopleArray.map(name =>
name.split(' ').map(word =>
word[0].toUpperCase() + word.slice(1).toLowerCase()
).join(' ')
);
const capitalizedNames = capitalizeNames(namesHardest);
console.log(capitalizedNames);
Sorry I am late to party, I'd rather use array.from with closure
const namesHardest = ['emIly jack sMith', 'angeliNA Jolie', 'braD piTt'];
let conv=Array.from(namesHardest,a=>a.toLowerCase().replace(/\b[a-z]/g, function(letter) {
return letter.toUpperCase();
}))
console.log(conv);
let namesHardest = ['emIly sMith', 'angeliNA Jolie', 'braD piTt'];
namesHardest = namesHardest.map(val => {
let [first, last] = val.toLowerCase().split(' ');
first = first.replace(first[0], first[0].toUpperCase());
last = last.replace(last[0], last[0].toUpperCase());
return `${first} ${last}`
});
console.log(namesHardest);
Your logic is a bit off. First, for each string, you need to split it by spaces to get the first and last name. Then, you can upcase the first character of each string. See below:
const namesHardest = ['emIly sMith', 'angeliNA Jolie', 'braD piTt'];
const capitalizeName = (name) => `${name[0].toUpperCase()}${name.slice(1)}`;
const capitalizeNames = (peopleArray) => peopleArray.map(name => {
const [first, last] = name.toLowerCase().split(' ');
return `${capitalizeName(first)} ${capitalizeName(last)}`;
});
console.log(capitalizeNames(namesHardest))
I'm trying to write a JavaScript function to split a string by its delimiter ('/') and wanted to return its path combination in an array.
Input:
"Global/Europe/UK/London"
Desired Output:
["Global","Global/Europe","Global/Europe/UK"]
I tried the below recursive function, but for some reason the array contains only a single value.
function splitPath(str) {
var output = [];
if (str.lastIndexOf('/') !== -1) {
str = str.split("/").slice(0, -1).join("/");
output.push(str);
splitPath(str);
}
//console.log(output);
return output;
}
Please let me know if there's any straight way to achieve this in JavaScript.
Thanks.
Using Array#reduce
let input = "Global/Europe/UK/London";
let output = input.split("/").slice(0, -1).reduce((acc, item, index) => {
acc.push(index ? acc[index - 1] + '/' + item : item);
return acc;
}, []);
console.log(output);
You could split the string and map with the parts from the beginning by using only the parts without the last one.
var string = "Global/Europe/UK/London",
grouped = string
.split('/')
.slice(0, -1)
.map(function (_, i, a) {
return a.slice(0, i + 1).join('/');
});
console.log(grouped);
Here's a way to split and then iteratively add the parts:
function splitPath(str) {
const parts = str.split("/");
let head = parts.shift();
const result = [head];
for (const part of parts) {
head += "/" + part;
result.push(head);
}
return result;
}
console.log(splitPath("Global/Europe/UK/London"))
How about this ?
let output = [];
let input = str.split('/');
input.reduce((acc,v, i, arr) => { output.push(acc + "/"+ v ); return acc + "/"+ v; })
'Global/Europe/UK/London'
.split('/')
.map(
(item, i, items) => {
return items.slice(0, i+1).join('/');
}
)