How to group different letters (not necessarily consecutive) using a regex - javascript

The example below results as expected:
const str = "abbcccddddeeeeeffffff";
const res = str.match(/(.)\1*/g);
console.log(res);
But if I try to group non consecutive letters:
const str = "abxbcxccdxdddexeeeefxfffffxx";
const res = str.match(/(.)\1*/g);
console.log(res);
I would like to get somethig like this:
[ 'a', 'bb', 'xxxxxxx', 'ccc', 'dddd', 'eeeee', 'ffffff']

Sort the string before applying the Regex :
const str = "abxbcxccdxdddexeeeefxfffffxx";
const res = [...str].sort().join('').match(/(.)\1*/g);
console.log(res);
If you absoloutely want them in that order, you can dedup the string and match the letters individually
const str = "abzzzbcxccdxdddexeeeefxfffffxx";
const res = [];
[...new Set(str)].forEach(letter => {
const reg = new RegExp(`${letter}`, "g");
res.push(str.match(reg).join(""));
});
console.log(res);

Here is way to do it without a regex, but you will need an array to hold the results:
var a = []; // (scratch space)
Array.prototype.map.call("abxbcxccdxdddexeeeefxfffffxx", c => c.charCodeAt(0))
.forEach(n => a[n] ? a[n] += String.fromCharCode(n) : a[n] = String.fromCharCode(n));
console.log(a.join(''));
Outputs: "abbcccddddeeeeeffffffxxxxxxx"
And if you need it in order, you can add m to keep a mapping of positions:
var a = [], m = []; // (scratch space; m maps chars to indexes)
Array.prototype.map.call("abxbcxccdxdddexeeeefxfffffxx", c => c.charCodeAt(0))
.forEach(n => (!m[n]&&(m[n]=m.length), a[m[n]] ? a[m[n]] += String.fromCharCode(n) : a[m[n]] = String.fromCharCode(n)));
console.log(a.join(''));
Outputs: "abbxxxxxxxcccddddeeeeeffffff"

Related

How can i show top 5 most frequently encountered words from the array of "bad words" in user input string

I have an array with bad words and function, with find it:
let words = textWords.split(' ');
console.log('words', words)
let badWords = listOfBadWords.join('|');
let regex = new RegExp(badWords, 'gi');
let matches = words.reduce((acc, word) => {
if (word.match(regex)) {
let match = word.toLowerCase();
acc[match] = (acc[match] || 0) + 1;
}
return acc;
}, {});
let sortedMatches = Object.entries(matches).sort((a, b) => b[1] - a[1]);
let top5 = sortedMatches.slice(0, 5).map(m => m[0]);
console.log(sortedMatches, top5); // in format [['word', numberOfUsing], ....]
How can i make the output like top 5 words most useable in format: word - numberOfUsing
I personally wouldn't use regular expression here. I'd create an object to count the words with from the badWords array and simply iterate the user's words to increase the counter. Something like that:
const badWords = ['cunt', 'shit', 'idiot', 'motherfucker', 'asshole', 'dickhead', 'slut', 'prick', 'whore', 'wanker'];
const userText = "I met this idiot today, he did behave like an asshole. This idiot treated me like a slut. Can't believe this idiot made me feeling like a cunt. Such an asshole, really. I tried to speak with this asshole, but he was just a dickhead.";
const counterObject = badWords.reduce((acc, curr) => {
acc[curr] = 0;
return acc;
}, {});
userText.split(/[\s,\.]/).forEach(
token => {
if (token in counterObject) counterObject[token]++;
}
);
const topWords = Object.entries(counterObject).sort((a, b) => b[1] - a[1]).slice(0, 5);
console.log(topWords);
I would do it like this
const listOfBadWords = ['is', 'or'];
const badWordsFound = [];
const userString = 'This is a test, works or not, is to be seen';
for(i = 0; i < listOfBadWords.length; i++){
const matches = (userString.match(new RegExp(listOfBadWords[i], 'g')) || []).length;
if(matches)
badWordsFound.push([listOfBadWords[i], matches]);
}
const sorted = badWordsFound.sort((a, b) => b[1] - a[1]);
console.log(sorted);

how can i count chars from word which in the array?

i have an array ["academy"] and i need count chars from the string in the array.
output:
a:2
c:1
d:1
e:1
m:1
y:1
like this
i tried two for loops
function sumChar(arr){
let alph="abcdefghijklmnopqrstuvxyz";
let count=0;
for (const iterator of arr) {
for(let i=0; i<alph.length; i++){
if(iterator.charAt(i)==alph[i]){
count++;
console.log(`${iterator[i]} : ${count}`);
count=0;
}
}
}
}
console.log(sumChar(["abdulloh"]));
it works wrong
Output:
a : 1
b : 1
h : 1
undefined
Here's a concise method. [...new Set(word.split(''))] creates an array of letters omitting any duplicates. .map takes each letter from that array and runs it through the length checker. ({ [m]: word.split(m).length - 1 }) sets the letter as the object key and the word.split(m).length - 1is a quick way to determine how many times that letter shows up.
const countLetters = word => (
[...new Set(word.split(''))].map(m => ({
[m]: word.split(m).length - 1
})))
console.log(countLetters("academy"))
You can check the occurrences using regex also. in this i made a method which checks for the character in the string. Hope it helps.
word: string = 'abcdefghijklkmnopqrstuvwxyzgg';
charsArrayWithCount = {};
CheckWordCount(): void {
for(var i = 0;i < this.word.length; i++){
if(this.charsArrayWithCount[this.word[i]] === undefined){
this.charsArrayWithCount[this.word[i]] = this.charCount(this.word, this.word[i]);
}
}
console.log(this.charsArrayWithCount);
}
charCount(string, char) {
let expression = new RegExp(char, "g");
return string.match(expression).length;
}
You can simply achieve this requirement with the help of Array.reduce() method.
Live Demo :
const arr = ["academy"];
const res = arr.map(word => {
return word.split('').reduce((obj, cur) => {
obj[cur] = obj[cur] ? obj[cur] + 1 : 1
return obj;
}, {});
});
console.log(res);
I think this is the simplest:
const input = 'academy';
const res = {};
input.split('').forEach(a => res[a] = (res[a] ?? 0) + 1);
console.log(res);

How to filter input value when a specific value is typed

I need to listen to an input and get its value dynamically,when a specific "flag" happens to be typed,get whatever is typed next until a flag appears again.
let me explain :
lets say i have an array of "flags"
let flags = ['foo','bar','baz']
and i have an input to listen which gives me the following string (dynamically,character by character):
let input = "whateveridontneedthatfoodavidbarjennifer-andrew-billbazericfoojohnbarchristen"
*foo and bar appear twice and baz once
i want somehow to create,maybe an object like this :
{
foo: ["david","john"],
bar: ["jennifer-andrew-bill","christen"],
baz: ["eric"]
}
or 3 separate arrays,i dont really care about the structure as long i filter the value properly
Good answer from #Apple BS, I just want to propose this syntax:
const flags = ['foo', 'bar', 'baz']
const str = 'whateveridontneedthatfoodavidbarjennifer-andrew-billbazericfoojohnbarchristen'
const strSplit = str.split(new RegExp(`(${flags.join('|')})`, 'g'))
const obj = Object.fromEntries(flags.map(f => [f, []]))
strSplit.forEach((el, i) => {
if (flags.includes(el)) obj[el].push(strSplit[i + 1])
})
console.log(obj)
EDIT:
There is an other version using regex capture groups.
const str = 'whateveridontneedthatfoodavidbarjennifer-andrew-billbazericfoojohnbarchristen'
const flags = ['foo', 'bar', 'baz'], flagsJoin = flags.join('|')
const obj = Object.fromEntries(flags.map(f => [f, []]))
const regex = new RegExp(`(${flagsJoin})(.*?)(?=${flagsJoin}|$)`, 'g')
for (const [, flag, sub] of str.matchAll(regex)) obj[flag].push(sub)
console.log(obj)
First, construct a regex:
let regex = '('; // parenthesis is added for capturing groups, which means the flags will be captured too
for (f of flags) regex += f + '|';
regex = new RegExp(regex.substring(0, regex.length - 1) + ')', 'g'); // construct the regex with global flag
// regex = /(foo|bar|baz)/g
Then, split the string:
s = s.split(regex) // ["whateveridontneedthat", "foo", "david", "bar", "jennifer-andrew-bill", "baz", "eric", "foo", "john", "bar", "christen"]
Finally, loop through the splitted string and add them to the object.
Below is the full example:
let flags = ['foo', 'bar', 'baz'];
let s = "whateveridontneedthatfoodavidbarjennifer-andrew-billbazericfoojohnbarchristen";
let regex = '(';
let obj = {};
for (f of flags) regex += f + '|';
regex = new RegExp(regex.substring(0, regex.length - 1) + ')', 'g');
s = s.split(regex);
for (let i = 0; i < s.length; i++) {
for (let j = 0; j < flags.length; j++) { // checking for flags
if (s[i] == flags[j]) { // found the flag
if (flags[j] in obj) obj[flags[j]].push(s[i + 1]); // array exist in object
else obj[flags[j]] = [s[i + 1]]; // create array in object
i++; // skip next s[i]
break; // s[i] can only be one of the flag
}
}
}
console.log(obj);
On top of #AppleBS's and #Jean Will's answer,
Just simplify the for loop.
const flags = ["foo", "bar", "baz"];
const str =
"whateveridontneedthatfoodavidbarjennifer-andrew-billbazericfoojohnbarchristen";
const strSplit = str.split(new RegExp(`(${flags.join("|")})`, "g"));
const output = strSplit.reduce((carry, item, idx, arr) => {
if (idx !== 0) {
if (idx % 2 === 0) carry[arr[idx - 1]].push(item);
else if (!carry[item]) carry[item] = [];
}
return carry;
}, {});
console.log(output);

wrap a function in javascript

let str = "i am writing an algorithm.";
//function to count alphabets
const alphabet_count = (str) => str.length;
//function to count words
const word_count = (str) => str.split(" ").length;
//function to count vowel
const vowel_count = (str) => (str.match(/[aeiou]/gi)).length;
//here i am trying to wrap all three functions in one
const sentence_read() = {alphabet_count(), word_count(), vowel_count()};
I am trying to trying to wrap all three functions in one.
const sentence_read = (str) => [alphabet_count(str), word_count(str), vowel_count(str)]
will return an array with your 3 results.
Usage :
let str = "a word";
console.log(sentence_read(str)) // output : [6, 2, 2]
Using a template string
let str = "i am writing an algorithm.";
// function to count alphabets
const alphabet_count = (str) => str.length;
// function to count words
const word_count = (str) => str.split(" ").length;
//function to count vowel
const vowel_count = (str) => (str.match(/[aeiou]/gi)).length;
const sentence_read = (str) => `a_c : ${alphabet_count(str)}, w_c : ${word_count(str)}, v_c : ${vowel_count(str)}`
console.log(sentence_read(str)) // a_c : 26, w_c : 5, v_c : 8
If you want to group the functions in an object, you can use:
const str = "i am writing an algorithm.";
const counter = {
alphabet: (s) => s.length,
word: (s) => s.split(" ").length,
vowel: (s) => (s.match(/[aeiou]/gi)).length
}
const count = (unit, str) => {
if(!counter[unit]) throw Error('Unit does not exist')
return counter[unit](str)
}
console.log(count('alphabet', str)) // 26
console.log(count('word', str)) // 5
console.log(count('vowel', str)) // 8

Parsing JavaScript string into 2 arrays

You have a string that is in a following format: "Applejack=A.J.+Applecar,Lemon+Vodka=AlfieCocktail+ Sunset + SexOnTheBeach" and etc.
In Javascript (use .split()), write code to parse a string like this(can be 100000 characters long) that puts the input in 2 different arrays(array key, array values) such that the arrays would llok like the following:
key = ["Applejack", "Lemon+Vodka"]
values = ["A.J+Applecar","AlfieCocktail+Sunset+SexOnTheBeach"]
key = string.split(',').map(x=>x.split("=")[0])
values = string.split(',').map(x=>x.split("=")[1])
You could do something like this
var str = "Applejack=A.J.+Applecar,Lemon+Vodka=AlfieCocktail+ Sunset + SexOnTheBeach";
var first = str.split(',');
var keys = [];
var values = [];
for(let i = 0; i < first.length; i++){
let in_two = first[i].split('=');
keys.push(in_two[0]);
values.push(in_two[1]);
}
console.log(keys);
console.log(values);
You can do it like this:
let str = "Applejack=A.J.+Applecar,Lemon+Vodka=AlfieCocktail+ Sunset + SexOnTheBeach";
let allValues = str.split(','), keys = [], values = [];
allValues.forEach(value => {
const [k,v] = value.split('=');
keys.push(k);
values.push(v);
})
console.log(keys,values);
You can simply use map with reduce.
const str =
"Applejack=A.J.+Applecar,Lemon+Vodka=AlfieCocktail+ Sunset + SexOnTheBeach";
const [keys, values] = str
.split(",")
.map((item) => item.split("="))
.reduce(
(acc, item) => [acc[0].concat(item[0]), acc[1].concat(item[1])],
[[], []]
);
console.log(keys, values);

Categories