93

Is it possible to combine regular expressions in javascript.

For ex:

 var lower = /[a-z]/;
 var upper = /[A-Z]/;
 var alpha = upper|lower;//Is this possible?

ie. can i assign regular expressions to variables and combine those variables using pattern matching characters as we do in regular expressions

Alan Moore
  • 73,866
  • 12
  • 100
  • 156
Jinu Joseph Daniel
  • 5,864
  • 15
  • 60
  • 90
  • Do you have two separate regexps or just want `/[a-zA-Z]/`? – J. K. Feb 09 '12 at 15:05
  • I know that....I need to know whether this is possible – Jinu Joseph Daniel Feb 09 '12 at 15:07
  • 2
    possible duplicate of [Combine Regexp](http://stackoverflow.com/questions/869809/combine-regexp) – Toon Krijthe Feb 09 '12 at 21:12
  • 2
    The problem with all of the answers is that flags will get blown away. You can't combine arbitrary regular expressions in JavaScript because it lacks the (?flags:matchtext) construct. – MkV Aug 25 '13 at 06:50
  • 1
    Yes, that's a particularly useful [feature of Perl's extended regular expressions](http://perldoc.perl.org/perlre.html#(%3f%5ealuimsx%3apattern)); there's no way to do this in JavaScript except a reimplementation or wrapper to replace native regex functionality (e.g. [XRegExp](http://xregexp.com/)). – Jordan Gray Aug 28 '13 at 16:32

6 Answers6

101

The answer is yes! You have to initialize the variable under the RegExp class:

var lower = new RegExp(/--RegexCode--/);
var upper = new RegExp(/--RegexCode--/);

hence, regex can be dynamically created. After creation:

"sampleString".replace(/--whatever it should do--/);

Then you can combine them normally, yes.

var finalRe = new RegExp(lower.source + "|" + upper.source);
Bry6n
  • 1,879
  • 1
  • 12
  • 20
  • 11
    lower and upper can be also be regular expressions literals. – brabec Aug 13 '14 at 10:04
  • 7
    Is there any difference to `new RegExp(/a/)` and just `/a/`? The latter already creates a RegExp instance. – rgov Jun 26 '18 at 02:42
  • 5
    For anybody else unsure, the key part of this for me was using .source on the RegExp literal I'd created to concatenate it into a string literal. – Luke Oct 06 '20 at 11:43
43

If regexps are not known beforehand,

var one = /[a-z]/;
var two = /[A-Z]/;

var one_or_two = new RegExp("(" + one.source + ")|(" + two.source + ")")
georg
  • 211,518
  • 52
  • 313
  • 390
13

use a general function:

const getComposedRegex = (...regexes) => new RegExp(regexes.map(regex => regex.source).join("|"))

Then call it with any number of Regexes.

const reg1 = /[w]{3}/i
const reg2 = /http/i

const composedReg = getComposedRegex(reg1, reg2)
Ben Carp
  • 24,214
  • 9
  • 60
  • 72
8

If this is something you only need to do once or twice, I'd stick with doing it on a per-case basis as suggested by other answers.

If you need to do a lot, however, a couple of helper functions might improve readability. For example:

var lower = /[a-z]/,
    upper = /[A-Z]/,
    digit = /[0-9]/;

// All of these are equivalent, and will evaluate to /(?:a-z)|(?:A-Z)|(?:0-9)/
var anum1 = RegExp.any(lower, upper, digit),
    anum2 = lower.or(upper).or(digit),
    anum3 = lower.or(upper, digit);

And here's the code if you want to use those functions:

RegExp.any = function() {
    var components = [],
        arg;

    for (var i = 0; i < arguments.length; i++) {
        arg = arguments[i];
        if (arg instanceof RegExp) {
            components = components.concat(arg._components || arg.source);
        }
    }

    var combined = new RegExp("(?:" + components.join(")|(?:") + ")");
    combined._components = components; // For chained calls to "or" method
    return combined;
};

RegExp.prototype.or = function() {
    var args = Array.prototype.slice.call(arguments);
    return RegExp.any.apply(null, [this].concat(args));
};

The alternatives are wrapped in non-capturing groups and combined with the disjunction operator, making this a somewhat more robust approach for more complex regular expressions.

Note that you will need to include this code before calling the helper functions!

Jordan Gray
  • 16,306
  • 3
  • 53
  • 69
4

Based on Bry6n answer here's a solution I use:

const Regexes = {
  Empty: /^$/,
  Minus: /^[-]$/,
  DotAndNumber: /^\.\d+$/,
  NumberAndDot: /^\d+\.$/,
  Float: /^[-]?\d+(\.\d+)?$/,
};

const orRegex = (...regexes) =>
  new RegExp(regexes.map(r => r.source).join('|'));

const FloatInputRegex = orRegex(
  Regexes.Empty,
  Regexes.Minus,
  Regexes.DotAndNumber,
  Regexes.NumberAndDot,
  Regexes.Float,
);
Sebastien Lorber
  • 89,644
  • 67
  • 288
  • 419
3
alpha = new RegExp( lower.source + "|" + upper.source );
console.log( alpha );
// /[a-z]|[A-Z]/
Esailija
  • 138,174
  • 23
  • 272
  • 326