107

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

5
  • Do you have two separate regexps or just want /[a-zA-Z]/? Commented Feb 9, 2012 at 15:05
  • I know that....I need to know whether this is possible Commented Feb 9, 2012 at 15:07
  • 2
    possible duplicate of Combine Regexp Commented Feb 9, 2012 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. Commented Aug 25, 2013 at 6:50
  • 1
    Yes, that's a particularly useful feature of Perl's extended regular expressions; there's no way to do this in JavaScript except a reimplementation or wrapper to replace native regex functionality (e.g. XRegExp). Commented Aug 28, 2013 at 16:32

8 Answers 8

116

The answer is yes!

 let lower = /[a-z]/;
 let upper = /[A-Z]/;

Then you can combine them dynamically by using the .source attribute:

let finalRe = new RegExp(lower.source + "|" + upper.source);
Sign up to request clarification or add additional context in comments.

5 Comments

lower and upper can be also be regular expressions literals.
Is there any difference to new RegExp(/a/) and just /a/? The latter already creates a RegExp instance.
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.
Check out Jordan's more robust answer below. This answer will work in simple cases but will fail or cause unexpected results with more advanced regular expressions (e.g. capturing groups).
It does not work. It is an OR. What about and AND
45

If regexps are not known beforehand,

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

var one_or_two = new RegExp("(" + one.source + ")|(" + two.source + ")")

Comments

19

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)

Comments

7

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!

Comments

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,
);

Comments

3
alpha = new RegExp( lower.source + "|" + upper.source );
console.log( alpha );
// /[a-z]|[A-Z]/

Comments

1

For those looking for a simple example with modern syntax:

const lower = /[a-z]/;
const upper = /[A-Z]/;
const alpha = new RegExp(`(${lower.source}|${upper.source})`);

This approach is not only useful for dynamic regex but also for readability.

Comments

0

Another function, which also merges the /flags:

function combineRegExp(...patterns) {
  const pattern = patterns.map(p => p.source).join("|")
  const flags = new Set(patterns.flatMap(p => [...p.flags]))
  return new RegExp(pattern, [...flags].join(""))
}

1 Comment

Could you provide an example to explain how this improves on existing answers?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.