Search code examples
javascriptregexfull-text-searchfind-occurrences

RegExp only - check if text contains specified character within provided range of occurrences


I would like to check if f.e letter "a" occurs between 3 and 5 times (inclusive), in total, within provided text input.

Given:

  1. zayaaxaawv <- 5 of "a", passed
  2. zayaxawva <- 4 of "a", passed
  3. zaaay <- 3 of "a", passed
  4. zayax <- 2 of "a", failed
  5. zayaaxaaaw <- 6 of "a", failed

Examples 1-3 passed and 4-5 failed.

I know it can be done in JavaScript without using RegExp, f.e:

const txt = `zayaxawva`;
const charCountByFilter = [...txt].filter(letter => letter === 'a').length;
const charCountByMatch = txt.match(/a/g).length;

console.log('isInRange by filter', isInRange(charCountByFilter));
console.log('isInRange by match', isInRange(charCountByMatch));

function isInRange(value) {
    return value >= 3 && value <= 5;
}

However, is it possible to do it entirely by RegExp? I thought of something similar to/a{3,5}/.test(txt), but it only counts subsequent "a" chars, not all of them.


Solution

  • You can use

    ^(?:[^a]*a){3,5}[^a]*$
    

    See the regex demo. Details:

    • ^ - start of a string anchor
    • (?:[^a]*a){3,5} - a non-capturing group matching three, four or five occurrences of
      • [^a]* - zero or more chars other than a
      • a - an a char
    • [^a]* - zero or more chars other than a
    • $ - end of the string anchor.

    See the JavaScript demo:

    const strings = ['zayaaxaawv','zayaxawva','zaaay','zayax','zayaaxaaaw'];
    const l = 'a', min = 3, max = 5;
    const rx = new RegExp(`^(?:[^${l}]*${l}){${min},${max}}[^${l}]*$`);
    strings.forEach(x => console.log(x, '=>', rx.test(x)));