RegExp.prototype.source

Returns the pattern text of a regular expression without the enclosing slashes or flags.

Signature
get RegExp.prototype.source
  • Added in JavaScript ES3 (1999)

Return value

stringThe source text of the pattern, escaped so that wrapping it in forward slashes yields a valid regex literal. An empty pattern returns "(?:)".

Errors

TypeError if accessed on a value that is not a RegExp object (other than RegExp.prototype itself).

Changelog

  • PHP ES5The escaping of forward slashes and line terminators, and the "(?:)" result for an empty pattern, were standardised; earlier engines disagreed.
  • PHP ES6source became an accessor on RegExp.prototype rather than an own data property of each instance, so RegExp.prototype.source itself returns "(?:)".

source is the pattern with the delimiters stripped: /^\d+$/gi.source is "^\d+$". It is what you need to take a regex apart and put it back together — the flags live on flags, and String(re) gives you the whole literal including both.

Composing patterns

The main use is building a large regex from small named pieces. Keep each fragment as its own literal so your editor still syntax-highlights it, then join the source strings inside new RegExp(). Wrap fragments containing alternation in (?:...) before concatenating, or a|b will bind across the seam and match something you never intended.

The escaping is deliberate

Forward slashes come back as \/ and raw newlines as \n, so "/" + re.source + "/" is always a syntactically valid literal. An empty pattern reports "(?:)" for the same reason — // would start a comment.

Round-tripping through new RegExp(re.source, re.flags) reproduces the regex exactly, except that the copy starts with lastIndex at 0.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Assemble a long URL or log-line pattern from small, individually testable fragments
  • Store a regex in JSON by saving source and flags separately
  • Clone a regex with different flags without hardcoding the pattern twice

Frequently asked questions

How do I combine two regular expressions in JavaScript?

Concatenate their source strings inside new RegExp(): new RegExp(a.source + b.source, flags). Wrap each fragment in a non-capturing group (?:...) first if it contains a top-level alternation, otherwise the | will span the join.

Why does an empty regex have source "(?:)"?

Because the value must remain a valid pattern when wrapped in slashes, and // would be parsed as a line comment. "(?:)" is an empty non-capturing group, which matches the empty string just like // does.

How is source different from toString()?

source is the pattern alone; toString() (and String(re)) returns the complete literal including the slashes and the flags. Use source when you are rebuilding a pattern, toString() when you are displaying or logging one.

More examples

Building one pattern from named fragments

Each fragment stays a real regex literal you can test on its own, and joining their source strings produces the full anchored pattern. Fragments with a top-level | would need their own (?:...) wrapper first.

Example · javascript
const scheme = /https?:\/\//;
const host   = /[\w.-]+/;
const path   = /\/\S*/;

const url = new RegExp(
  "^" + [scheme, host, path].map(p => p.source).join("") + "$"
);

console.log(url.source);
console.log(url.test("https://example.com/a/b")); // true
console.log(url.test("ftp://example.com/a"));     // false

Round-tripping a regex

source plus flags fully reconstructs the pattern, which is how you persist a regex to JSON. The one thing that does not survive is lastIndex, which is usually what you want.

Example · javascript
const original = /a\/b/gi;
original.lastIndex = 3;

const copy = new RegExp(original.source, original.flags);

console.log(copy.source === original.source); // true
console.log(String(copy) === String(original)); // true
console.log(copy.lastIndex);      // 0 - state is not copied
console.log(original.lastIndex);  // 3

Discussion

  • Be the first to comment on this lesson.