#Regex, match strings that at most contain one or more elements

11 messages · Page 1 of 1 (latest)

stable cypress
#

I want a regex to match the following strings: "foo", "bar", "foo/bar" (the "/" is important), but not "foo/bar/baz" or "foo/baz" etc.

is that possible? I don't even know how this task is called, so I wouldn't know what to google for...

twin tiger
#

Use or operator ^(foo|bar|foo\/bar)$

stable cypress
#

I just realized that the example might not generalize well to my actual problem.
so it works, but it should also work for any combination of keywords, e.g. when I want to instead match "foo", "bar", "foo/bar", "foo/baz", "bar/baz" and "foo/bar/baz", the regex would need to be ^(foo|bar|baz|foo\/bar|foo\/baz|bar\/baz|foo\/bar\/baz)$

and my actual problem is how I generate that search string for any array of keywords in Javascript 😅

twin tiger
#

If you want it to be dynamic, regex is not the best option for that

#

You better do it through Javascript

stable cypress
#

Okay but in the end I need a regex string, since I'm going to query MongoDB with it.
So I somehow have to generate the string above for any array of words

#

probably a permutation problem of sorts

#

okay I might have found something (shamelessly borrowed from https://code-boxx.com/javascript-permutations-combinations/)

function allCombinations (items) {
    let results = [];
    for (let slots = items.length; slots > 0; slots--) {
      for (let loop = 0; loop < items.length - slots + 1; loop++) {
        let key = results.length;
        results[key] = [];
        for (let i = loop; i < loop + slots; i++) {
          results[key].push(items[i]);
        }
      }
    }
    return results;
}

let searchStr = '^(';

let combo = allCombinations(['foo', 'bar', 'baz']);
combo.forEach(comb => {
  searchStr += comb.join('\/') + '|';
});

searchStr += ')$';
let regex = RegExp(searchStr);
weary mesa
#

I don't know if this works in all scenarios. For example, with inputs of ['foo', 'bar', 'baz'] the output is ^(foo/bar/baz|foo/bar|bar/baz|foo|bar|baz|)$ which looks like it's missing a few

#

like you have foo/bar but do you also need bar/foo?

weary mesa
#

I think this might work:

function addWords(wordstack, wordlist){
  
  var result = wordstack;
  var stackEmpty = wordstack == ""
  var delimiter = stackEmpty ? "" : "\\/";
  
  for(var i = 0; i < wordlist.length; i++){
    let newList = [...wordlist]
    newList.splice(i, 1)
    result += "|" + addWords(wordstack + delimiter + wordlist[i], newList)
  }
  return result;
}

function makeRegex(wordlist){
  if(wordlist.length == 0)
    return null;
  
  let result = "^(";
  
  result += addWords("", wordlist);
  
  result += ")$";
  return result;
}