MattYao
MattYao

Reputation: 2555

How to write a efficient way in Javascript to deal with matching pattern?

I would like to generate strings that match a certain pattern. For example, the function would take two parameters:

function parsePattern(pattern, string) {}

And the accepted pattern could be '(hello|hi), %i, (how are you|nice to see you)' and if the 2nd param is set as 'John' in this way

parsePattern('(hello|hi), %i, (how are you|nice to see you)', 'John')

I would like the output to have all the possible combinations:

 'hello, John, how are you'
 'hello, John, nice to see you'
 'hi, John, how are you'
 'hi, John, nice to see you'

What's the best way to achieve this?

Upvotes: 0

Views: 155

Answers (1)

Boatmarker
Boatmarker

Reputation: 196

You're looking to do the reverse of what regex is normally used for, so it wouldn't be possible for more generalized regex patterns like \w+. But if you're just looking to generate results for the A|B type of patterns like in your example, here's some code that will accomplish this. This makes use of StackOverflow's own formatUnicorn function as well as a Cartesian product function as given here. You can replace these with your own, of course.

JSFiddle: https://jsfiddle.net/aro108zc/

String.prototype.formatUnicorn = String.prototype.formatUnicorn ||
  function () {
  "use strict";
  var str = this.toString();
  if (arguments.length) {
    var t = typeof arguments[0];
    var key;
    var args = ("string" === t || "number" === t) ?
        Array.prototype.slice.call(arguments)
    : arguments[0];

    for (key in args) {
      str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]);
    }
  }

  return str;
};

function cartesianProduct(arr) {
  return arr.reduce(function (a, b) {
    return a.map(function (x) {
      return b.map(function (y) {
        return x.concat([y]);
      })
    }).reduce(function (a, b) { return a.concat(b) }, [])
  }, [[]])
}

function parsePattern(pattern, str) {
  var regex = /\(([^|()]+\|)*[^|()]+\)/g;
  var results = [];

  var matches = pattern.match(regex);

  // replace input string match groups with format strings
  matches.forEach(function (el, idx) {
    pattern = pattern.replace(el, '{' + (idx + 1) + '}');
  });

  // split matches into parts
  var matchesSplit = [];

  matches.forEach(function (el, idx) {
    matchesSplit[idx] = el.replace(/[()]/g, '').split('|');
  });

  // generate result strings
  matchesSplit.splice(0, 0, [str]);

  cartesianProduct(matchesSplit).forEach(function (el) {
    results.push(pattern.formatUnicorn(el));
  });

  return results;
}

Upvotes: 1

Related Questions