So I have the below setup where a user inputs text and I want to see if any of the inputted characters match the words. It all works great when I input say.
const input = 'memb';
but if do something like this.
const input = 'member has';
Then it returns false. It should stay true if it finds a match of characters which it does, member is a match. Member has is also a match as the characters m, e, m, b, e, r is still a match event though h, a, s doesn't match any the other words.
Anyone know how I can get it to keep returning true if the characters match ?
const input = 'member has';
const inputLower = input.toLowerCase();
const words = ['member', 'support', 'life'];
const result = words.some(word => {
const words = word.split(',');
return words.some(r => r.toLowerCase().includes(inputLower));
});
console.log('result = ', result);
You can add the reverse logic, where you also check whether inputLower includes r:
const input = 'memb has';
let inputLower = input.toLowerCase();
const words = ['member', 'support', 'life'];
const result = words.some(word => {
const words = word.split(',');
return words.some(r => {
if (~inputLower.indexOf( " " )) {
// only check the first word if there are multiple
inputLower = inputLower.substring( 0, inputLower.indexOf( " " ) );
}
return r.toLowerCase().includes(inputLower) || inputLower.includes(r.toLowerCase());
});
});
console.log('result = ', result);
Related
A function takes one string argument and outputs a string.
It should remove all vowels from the supplied string if the string contains mostly vowels, otherwise return the supplied string without modification.
Specification:
A string is considered to contain mostly vowels if it has more vowels (a, e, i, o, u) than consonants (b, c, d, f, g, h, j, k, l, m, n, p, q, r, s, t, v, w, x, y, z), ignoring all non-alphabetic characters from the count.
If a string contains mostly vowels, the result should have excess whitespace removed - there should be no leading or trailing whitespace, nor any double spaces within the returned string.
Strings may contain more than one word. Spaces between words must be preserved, except for when the entire word has been removed.
For example, the string "hello" would remain hello.
However, the string "adieu" would become d.
This is what I have tried to no success so far:
function removeVowel(input) {
//function that takes string as input
//function returns an object containing vowel count without case in account.
function vowelCount(input) {
//to get vowel count using string.match
let arrVowels =input.match(/[aeiouAEIOU]+?/g);
//acc=accumulator, curr=current value
let countVowCons= arrVowels.reduce(function (acc, curr) {
if (typeof acc[curr.toLowerCase()] == 'undefined') {
acc[curr.toLowerCase()] = 1;
}
else {
acc[curr.toLowerCase()] += 1;
}
return acc;
// the blank object below is default value of the acc (accumulator)
}, {});
countVowCons.NonVowels= input.match(/[^aeiouAEIOU]+?/g).length;
if(arrVowels > countVowCons.NoVowels) {
//remove vowels from string & return new string
const noVowels = input.replace(/[aeiou]/gi, '')
} else {
// return supplied string withoout modification
return input
}
}
}
I know I´m doing a lot of things wrong, could anyone point me in the right direction?
Expected: "hello"
Received: undefined
Expected: "hrd d"
Received: undefined
const maybeDisemvowel = (originalString) => {
const onlyConsonants = originalString.replace(/[^bcdfghjklmnpqrstvwxys]/gi, '')
const onlyVowels = originalString.replace(/[^aeoiu]/gi, '')
const withoutVowels = originalString.replace(/[aeoiu]/gi, '')
const shouldReturnOriginal = onlyConsonants.length > onlyVowels.length
return shouldReturnOriginal
? originalString
: withoutVowels.trim().replace(/\s+/g, ' ')
}
console.log(maybeDisemvowel(' abb b')) // no change
console.log(maybeDisemvowel('aaaaaa bbb aaa bbb b')) // change
console.log(maybeDisemvowel('aa ab bba ')) // change
you can do something like this
const transform = string => {
const letters = string.replace(/\W/gi, '')
const notVowels = letters.replace(/[aeiou]/gi, '')
if(letters.length < notVowels.length * 2){
return string
}
return string.replace(/[aeiou]/gi, '').split(' ').filter(word => word).join(' ').trim()
}
console.log(transform('hello'))
console.log(transform('Adieu'))
console.log(transform('Adieu hello aaaaaaaaaaaa b'))
console.log(transform('I heard a ad'))
function maybeDisemvowel() is not nesccesary and its not passing value into that other function.
//pass input Pneumonia
function vowelCount(input) {
//to get vowel count using string.match
let arrVowels = input.match(/[\saeiouAEIOU]+?/g);
//arrVowels = ['e', 'u', 'o', 'i', 'a']
// now simply compare length of input minus all vowels
// with vowels you found in word
// inp 9 - arrVow 5 < 5
// 4 < 5 => true
//you tried compare with variable that was not defined before
//that value was in if statement which is out of reach
if (input.length - arrVowels.length < arrVowels.length) {
//remove vowels from string & return new string
//you forget return this value
return input.replace(/[\saeiouAEIOU]/gi, '');
} else {
// return supplied string withoout modification
return input;
}
}
I have a string returned from an endpoint in which I need to add certain parts of the string together in order to produce two different values.
Example response:
149,226;147,226;146,224
Now I know I can use the unary plus operator to force the string to be treated as a number like so.
var num1 = '20',
num2 = '22';
var total = (+num1) + (+num2);
or I could do some conversion like so
var number1 = parseInt(num1);
var number2 = parseInt(num2);
var total = number1 + number2;
either of these work fine however this is not what I am looking for exactly.
I want to take this result
149,226;147,226;146,224
Then add all the numbers before the first comer together so that would be (149, 147, 146) to produce one result and then add all the number after the second comer together (226, 226, 224).
I know I probably need some sort of reg expression for this I just dont know what.
You can just use string.split, twice, one for the ; and then again for the ,. And put this through array.reduce.
eg.
var str = '149,226;147,226;146,224';
var result = str.split(';')
.reduce((a,v) => {
var vv = v.split(',');
a[0] += vv[0] | 0;
a[1] += vv[1] | 0;
return a;
}, [0, 0]);
console.log(result);
For a more generic solution, that could handle any number of sub strings, eg. 1,2,3;4,5,6, and also handle alternative split types, and cope with extra , or ;.
function sumStrings(str, outerSplit, innerSplit) {
return str.split(outerSplit || ';')
.filter(Boolean)
.reduce((a,v) => {
v.split(innerSplit || ',')
.filter(Boolean)
.forEach((v,ix) => {
a[ix] = (a[ix] | 0) + (v | 0);
});
return a;
}, []);
}
console.log(sumStrings(
'149,226;147,226;146,224'
));
console.log(sumStrings(
'149.226.201|147.226.112.|146.224.300|',
'|','.'));
//how about total of totals?
console.log(sumStrings(
'149,226;147,226;146,224'
).reduce((a,v) => a + v));
.as-console-wrapper {
min-height: 100%
}
You could do:
const myString = '149,226;147,226;146,224';
/*
* 1. you split the string by ';' to obtain an array of string couples
* then you split each couple by ','. In this way you end up with an array like this:
* [['149', '266'], ['147', '266'], ['146', '264']]
*/
const myNumbers = myString.split(';').map(numCouple => numCouple.split(','));
/*
* 2. you use Array.prototype.reduce() to calculate the sums
*/
const sum1 = myNumbers.reduce((sum, item) => {
return sum += parseInt(item[0]);
}, 0);
const sum2 = myNumbers.reduce((sum, item) => {
return sum += parseInt(item[1]);
}, 0);
// or, as an alternative:
const sumsObj = myNumbers.reduce((obj, item) => {
obj.sum1 += parseInt(item[0]);
obj.sum2 += parseInt(item[1]);
return obj;
}, { sum1: 0, sum2: 0 });
// or also:
const sumsArr = myNumbers.reduce((acc, item) => {
acc[0] += parseInt(item[0]);
acc[1] += parseInt(item[1]);
return acc;
}, [0, 0]);
// test
console.log('sum1:', sum1);
console.log('sum2:', sum2);
console.log('--------------');
console.log('sum1:', sumsObj.sum1);
console.log('sum2:', sumsObj.sum2);
console.log('--------------');
console.log('sum1:', sumsArr[0]);
console.log('sum2:', sumsArr[1]);
without using regex, one possible solution:
var c = '149,226;147,226;146,224'
var d = c.split(";")
var first = d.map(x=>Number(x.split(",")[0]))
var second= d.map(x=>Number(x.split(",")[1]))
console.log(first)
console.log(second)
let resultFirst = first.reduce((a,b) => a + b, 0);
let resultSecond = second.reduce((a,b) => a + b, 0);
console.log(resultFirst)
console.log(resultSecond)
Below supplies regex to String's .split to get the numbers by themselves. Then you could add every other number but I don't see why not just add them all in order.
const str = '149,226;147,226;146,224'
const total = str.split(/[;,]/).map(Number).reduce((a, b) => a + b)
console.log('total', total)
I got this one running:
const nums = ('149,226;147,226;146,224');
var firstNums = nums.match(/(?<=[0-9]*)[0-9]+(?=,)/gs);
var secondNums = nums.match(/(?<=[0-9]*)[0-9]+(?=;|$)/gs);
console.log(firstNums, secondNums);
let sumFirstNums = 0,
sumSecondNums = 0;
firstNums.map(x => {
sumFirstNums += +x;
})
console.log(sumFirstNums)
secondNums.map(x => {
sumSecondNums += +x;
})
console.log(sumSecondNums)
//If you want the result in the same format:
const finalResult = `${sumFirstNums}, ${sumSecondNums};`
console.log(finalResult)
;)
For that string format, you could use a single pattern with 2 capturing groups matching 1+ more digits between a comma, and asserting a ; or the end of the string at the right.
You refer to the group values by indexing into the match of every iteration.
(\d+),(\d+)(?=;|$)
The pattern matches
(\d+) Capture group 1, match 1+ digits
, Match a comma
(\d+) Capture group 2, match 1+ digits
(?=;|$) Positive lookahead, assert directly to the right a ; or end of the string
See a regex demo.
let result1 = 0;
let result2 = 0
for (const match of "149,226;147,226;146,224".matchAll(/(\d+),(\d+)(?=;|$)/g)) {
result1 += +match[1]
result2 += +match[2]
}
console.log(result1, result2);
I'm currently programming a Discord bot, and was wondering if it is possible to predict the wanted command if the input was incorrect.
For example, I have this list of words :
['help','meme','ping'],
and if the user inputs "hepl", would it somehow be possible to "guess" they meant to type help ?
One option would be to find a command whose levenshtein distance from the input is 2 or less:
// https://gist.github.com/andrei-m/982927
const getEditDistance=function(t,n){if(0==t.length)return n.length;if(0==n.length)return t.length;var e,h,r=[];for(e=0;e<=n.length;e++)r[e]=[e];for(h=0;h<=t.length;h++)r[0][h]=h;for(e=1;e<=n.length;e++)for(h=1;h<=t.length;h++)n.charAt(e-1)==t.charAt(h-1)?r[e][h]=r[e-1][h-1]:r[e][h]=Math.min(r[e-1][h-1]+1,Math.min(r[e][h-1]+1,r[e-1][h]+1));return r[n.length][t.length]};
const commands = ['help','meme','ping'];
const getCommand = (input) => {
if (commands.includes(input)) return input;
return commands.find(command => getEditDistance(input, command) <= 2);
};
console.log(getCommand('hepl'));
(2 is just a number, feel free to pick the tolerance you want - the higher it is, the more commands will be guessed at, but the more false positives there will be)
You can find hits and show many words in suggestion. If you want same you can use to show most hit word.
const words = ["help", "meme", "ping"];
const getHits = (word, wordToMatch, hits = 0) => {
if (!word.length || !wordToMatch.length) return hits;
let charW = word.slice(0, 1);
let index = wordToMatch.indexOf(charW);
if (index !== -1) {
return getHits(
word.slice(1),
String(wordToMatch.slice(0, index) + wordToMatch.substr(index + 1)),
hits + 1
);
}
return getHits(word.slice(1), wordToMatch, hits);
};
const getMatch = mword => {
return words.reduce((m, word) => {
m[word] = getHits(mword, word);
return m;
}, {});
};
const sort = obj => {
return Object.entries(obj).sort(
([_, value1], [__, value2]) => value2 - value1
);
};
console.log(getMatch("help"));
console.log(sort(getMatch("help")));
console.log(getMatch("me"));
console.log(sort(getMatch("me")));
.as-console-row {color: blue!important}
I have an array of strings. I need to display those elements into proper format. Like this example.
let array1 = ["WORLDWIDE_AGRICULTURAL - CA"," WORLDWIDE_INDUSTRIAL - MX"]
I have to display it like below:
let formattedArray = ["Worldwide Agricultural - CA","Worldwide Industrial - MX"]
There are multiple of elements so I have to save formatted strings into array. I have tried but it is not coming properly.
Any help is much appreciated.
if(array1.indexOf("WORLDWIDE_AGRICULTURAL")>=0 || array1.indexOf(" WORLDWIDE_INDUSTRIAL") >=0){ var locname1 = array1.split('-'); var locname2 =locname1[0].trim(); var locname3 = locaname1[1].trim(); var formattedArray = locname2.toUpperCase()+ ' - '+locname3.toUpeerCase();
But, it is coming in uppercase and i have to all formatted elements into array.
You could use .map() with .replace() and the replacement method to convert your capital groups into lowercase groups like so:
const array1 = ["WORLDWIDE_AGRICULTURAL - CA"," WORLDWIDE_INDUSTRIAL - MX"];
const res = array1.map(str =>
str.replace(/(\w)(\w+)_(\w)(\w+)/g, (_, a, b, c, d) =>
`${a}${b.toLowerCase()} ${c}${d.toLowerCase()}`
).trim()
);
console.log(res);
The expression first matchs the first character in the string and groups that in group a. It then groups the remaining characters in group b up until the underscore. Then, it groups the first character after the underscore (group c). Lastly, it groups the remaining characters up to the next space. Using the replacement method, we can change group b to lowercase, and group d to lowercase, giving you a capitalized string.
An alternate approach which would require less grouping is to extract the first character from the first and second group, and capitalize the rest:
const array1 = ["WORLDWIDE_AGRICULTURAL - CA"," WORLDWIDE_INDUSTRIAL - MX"];
const res = array1.map(str =>
str.replace(/(\w+)_(\w+)/g, (_, [a, ...b], [c, ...d]) =>
`${a}${b.join('').toLowerCase()} ${c}${d.join('').toLowerCase()}`
).trim()
);
console.log(res);
let array1 = ["WORLDWIDE_AGRICULTURAL - CA", " WORLDWIDE_INDUSTRIAL - MX"];
function titleCase(str) {
var splitStr = str.toLowerCase().split(' ');
for (var i = 0; i < splitStr.length; i++) {
if (splitStr[i].length > 2) {
splitStr[i] = splitStr[i].charAt(0).toUpperCase() + splitStr[i].substring(1);
} else {
splitStr[i] = splitStr[i].toUpperCase()
}
}
return splitStr.join(' ');
}
const formattedArray = array1.map((x) => titleCase(x));
console.log(formattedArray);
Here's what would match your current demonstrated requirement:
let array1 = ["WORLDWIDE_AGRICULTURAL - CA"," WORLDWIDE_INDUSTRIAL - MX"]
function formatter(str) {
let split = str.split("-")
let formattedFirst = split[0].replace(/_/g, " ")
.replace(/\w\S*/g, function(txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
});
return `${formattedFirst} - ${split[1]}`
}
let convertedArray = array1.map(formatter)
console.log(convertedArray);
First, it seems like you only want to format whats before the ' - ' so we split on that. Then using replace we turn the _ into ' ' after which we can convert to title casing by capitalizing the first letter and lower casing the rest. Afterwards, we recombine to restore the original format of the rest of the string
I am trying to make a function that loops through a word, identifies the first vowel found (if any) in the word, and then splits up the word after the vowel.
example input: 'super'
example output: 'su', 'per'
function consAy(word){
if(word[i].indexOf("a" >= 0) || word[i].indexOf("e" >= 0) || word[i].indexOf("i" >= 0) || word[i].indexOf("o" >= 0) || word[i].indexOf("u" >= 0)){
}
One way to do it is to use a regular expression to .match() the pattern you are looking for:
function consAy(word){
var result = word.match(/^([^aeiou]*[aeiou])(.+)$/i)
return result ? result.slice(1) : [word]
}
console.log( consAy('super') )
console.log( consAy('AMAZING') )
console.log( consAy('hi') )
console.log( consAy('why') )
The function I've shown returns an array. If there was a vowel that was not at the end then the array has two elements. If there was only a vowel at the end, or no vowel, then the array has one element that is the same as the input string.
A brief breakdown of the regex /^([^aeiou]*[aeiou])(.+)$/i:
^ // beginning of string
[^aeiou]* // match zero or more non-vowels
[aeiou] // match any vowel
.+ // match one or more of any character
$ // end of string
...where the parentheses are used to create capturing groups for the two parts of the string we want to separate, and the i after the / makes it case insensitive.
The .match() method returns null if there was no match, so that's what the ternary ?: expression is for. You can tweak that part if you want a different return value for the case where there was no match.
EDIT: I was asked for a non-regex solution. Here's one:
function consAy(word){
// loop from first to second-last character - don't bother testing the last
// character, because even if it's a vowel there are no letters after it
for (var i = 0; i < word.length - 1; i++) {
if ('aeiou'.indexOf(word[i].toLowerCase()) != -1) {
return [word.slice(0, i + 1), word.slice(i + 1)]
}
}
return [word]
}
console.log( consAy('super') )
console.log( consAy('AMAZING') )
console.log( consAy('hi') )
console.log( consAy('why') )
This assumes a reasonably modern browser, or Node.
const string = "FGHIJK";
const isVowel = c => c.match(/[AEIOU]/i);
const pos = [...string].findIndex(isVowel);
const truncatedString = `${[...string].slice(0, pos + 1)}`;
truncatedString; // "FGHI"
Edit
As has been pointed out, the above is significantly more hassle than it's worth. Without further ado, a much saner approach.
const string = "FGHIJK";
const vowels = /[aeiou]/i;
const truncateAfter = (string, marker) => {
const pos = string.search(marker);
const inString = pos >= 0;
return string.slice(0, inString ? pos : string.length);
};
const truncated = truncateAfter(string, vowels);
Without using a RegEx of any kind. Ye ole fashioned algorithm.
const truncateAfter = (string, markers) => {
let c = "";
let buffer = "";
for (let i = 0, l = string.length; i < l; i += 1) {
c = string[i];
buffer += c;
if (markers.includes(c)) {
break;
}
}
return buffer;
};
const truncatedString = truncateAfter(
"XYZABC",
["A", "E", "I", "O", "U"],
);
With RegEx golf.
const string = "BCDEFG";
const truncatedString = string.replace(/([aeiou]).*/i, "$1");
With a reduction.
const isVowel = c => /[aeiou]/i.test(c);
const last = str => str[str.length - 1];
const truncatedString = [...string].reduce((buffer, c) =>
isVowel(last(buffer)) ? buffer : buffer + c, "");
Via a dirty filter hack, that takes way too much power O(n**2).
const truncatedString = [...string]
.filter((_, i, arr) => i <= arr.search(/[aeiou]/i));
There are others, but I think that's enough to shake the cobwebs out of my brain, for now.
I always like to take opportunities to write incomprehensible array-based code, so with that in mind...
const regexMatcher = pattern => input => {
return input.match(pattern)
};
const splitAtFirstMatch = matcher => arrayLike => {
return [...arrayLike]
.reduce(([pre, post, matchFound], element) => {
const addPre = matchFound || matcher(element);
return [
matchFound ? pre :[...pre, element],
matchFound ? [...post, element] : post,
addPre
];
}, [[],[], false])
.slice(0, 2)
.map(resultArrays => resultArrays.join(''));
};
console.log(splitAtFirstMatch(regexMatcher(/[aeiou]/))('super'));