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

Viewed 76

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']
2 Answers

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