How to Use a Variable in a Regular Expression (JavaScript, Python, PHP)
Static regex patterns are easy:
const regex = /\d+/;
But what happens when your pattern depends on user input? When the word to match comes from a configuration file? When the search term is typed by a user?
function search(text, term) {
// How do I use `term` inside a regex?
}
This is where dynamic regex patterns become necessary.
The problem is that inserting variables into regex is surprisingly error-prone. Special characters in the variable can break the pattern, introduce security risks, or create performance issues.
This guide covers how to safely use variables in regex across JavaScript, Python, and PHP, with real production examples.
If you want to test dynamic patterns interactively, the Regex Tester is useful for experimenting.
The Core Problem: Special Characters in Input
When you insert a variable into a regex, the regex engine interprets special characters in the variable as regex syntax.
const term = "hello.world";
const regex = new RegExp(term);
This creates the pattern hello.world, where . matches ANY character, not a literal dot.
The pattern matches helloXworld, hello-world, hello_world —all of which may be unintended.
This is the most common bug in dynamic regex patterns.
JavaScript: Building a RegExp from a Variable
const searchTerm = "foo";
const regex = new RegExp(searchTerm, "gi");
The RegExp constructor takes a string and compiles it into a regex pattern.
Without escaping:
const searchTerm = "(foo)";
const regex = new RegExp(searchTerm);
// Matches "foo" as a capturing group, not literally "(foo)"
JavaScript: Escaping User Input
The safe approach is to escape special characters before inserting:
function escapeRegex(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
const userInput = "hello.world (test)";
const escaped = escapeRegex(userInput);
const regex = new RegExp(escaped, "gi");
console.log(regex.test("hello.world (test)")); // true
console.log(regex.test("helloXworld (test)")); // false
The escape function prepends a backslash to every regex special character.
JavaScript Example: Case-Insensitive Search
function searchInText(text, query) {
const escaped = query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const regex = new RegExp(escaped, "gi");
return text.match(regex);
}
const text = "Hello World. hello world. HELLO.";
const results = searchInText(text, "hello");
console.log(results); // ["Hello", "hello", "HELLO"]
This is a realistic search function, safe against user input with special characters.
JavaScript Example: Dynamic Replacement
function highlight(text, term) {
const escaped = term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const regex = new RegExp(`(${escaped})`, "gi");
return text.replace(regex, "<mark>$1</mark>");
}
console.log(highlight("Find foo and foo.bar", "foo"));
// "<mark>foo</mark> and <mark>foo</mark>.bar"
Notice that foo.bar is NOT highlighted —the escaped foo pattern correctly matches only literal foo.
JavaScript: The new RegExp() Pitfall
A common mistake:
const term = "\\d+";
const regex = new RegExp(term);
// This creates /\d+/, not /\\d+/
Because term contains \\d+, the string literal becomes \d+, which is the digit pattern, not a literal backslash followed by "d+".
This double-escaping confusion causes endless bugs.
Python: Building a Regex from a Variable
import re
search_term = "foo"
pattern = re.compile(search_term, re.IGNORECASE)
matches = pattern.findall("Hello foo Foo foo")
print(matches) # ['foo', 'Foo', 'foo']
Python: Escaping User Input
import re
def escape_regex(text):
return re.escape(text)
user_input = "hello.world (test)"
escaped = re.escape(user_input)
pattern = re.compile(escaped, re.IGNORECASE)
print(pattern.findall("hello.world (test) says helloXworld"))
# ['hello.world (test)']
Python's re.escape() handles escaping automatically. It is the standard way to use variables in Python regex.
Python Example: Dynamic Search Function
import re
def search_text(text, query):
escaped = re.escape(query)
pattern = re.compile(escaped, re.IGNORECASE)
return pattern.findall(text)
text = "Error: connection failed. error: timeout."
results = search_text(text, "error")
print(results) # ['Error', 'error']
PHP: Building a Regex from a Variable
$searchTerm = "foo";
$pattern = "/" . preg_quote($searchTerm, "/") . "/i";
$matches = [];
preg_match_all($pattern, "Hello foo Foo foo", $matches);
print_r($matches[0]);
// ['foo', 'Foo', 'foo']
PHP: The Second Parameter of preg_quote
PHP's preg_quote takes an optional second parameter —the delimiter to escape:
$searchTerm = "foo/bar";
$pattern = "/" . preg_quote($searchTerm, "/") . "/";
// Escapes the / inside $searchTerm too
This is easy to forget and causes subtle bugs when the input contains the delimiter.
Common Mistake #1: Forgetting to Escape
This is the most common mistake.
function findMatches(text, term) {
const regex = new RegExp(term, "gi"); // Bug: term is not escaped
return text.match(regex);
}
findMatches("foo.bar", "."); // Returns every character
The . becomes a wildcard instead of a literal dot.
Common Mistake #2: Double Escaping
const term = "\\.";
const regex = new RegExp(term);
// This matches a literal dot, because \\ becomes \
But if you pass \\. (already escaped), the regex engine sees \. which matches a literal dot. If you pass \. (single backslash in string), it becomes . (any character).
This backslash counting is the source of countless bugs.
Related reading: Common Regex Mistakes Developers Keep Making
Related reading: \d Is Less Efficient Than [0-9] —Node.js Regex Performance Deep Dive
Common Mistake #3: Building Regex Inside Loops
const terms = ["foo", "bar", "baz"];
const results = [];
terms.forEach(term => {
const regex = new RegExp(term, "gi"); // New regex each iteration
const match = text.match(regex);
if (match) results.push(...match);
});
This works but is inefficient for large datasets. The regex is recompiled every iteration.
Better: compile once, reuse.
const regexes = terms.map(term => new RegExp(escapeRegex(term), "gi"));
Common Mistake #4: Using Variable in Regex Literal
JavaScript does not support interpolation in regex literals:
const term = "foo";
const regex = /term/gi; // Matches literal "term", not the value of term
You MUST use new RegExp() for dynamic patterns.
Performance: Compile Once, Match Many
Regex compilation has a cost. For patterns that change frequently, the compilation overhead can be significant.
// Bad: recompiles every call
function searchBad(text, term) {
return text.match(new RegExp(escapeRegex(term), "gi"));
}
// Better: cache compiled regex
const regexCache = new Map();
function searchBetter(text, term) {
if (!regexCache.has(term)) {
regexCache.set(term, new RegExp(escapeRegex(term), "gi"));
}
return text.match(regexCache.get(term));
}
Python: Caching Compiled Patterns
import re
from functools import lru_cache
@lru_cache(maxsize=100)
def get_pattern(term):
return re.compile(re.escape(term), re.IGNORECASE)
def search_text(text, term):
pattern = get_pattern(term)
return pattern.findall(text)
Security: ReDoS (Regular Expression Denial of Service)
User-supplied regex patterns can cause catastrophic backtracking.
If you allow users to supply the raw pattern (not escaped), they could craft:
const evilPattern = "(a+)+b";
const regex = new RegExp(evilPattern);
regex.test("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
// CPU spike —possible denial of service
Never pass unsanitized user input directly to new RegExp().
Related reading: Regex Catastrophic Backtracking —How to Fix Regex That Freezes Your App
When to Escape vs When to Not
| Use Case | Escape? |
|---|---|
| User search input | Always escape |
| Config file values | Always escape |
| Hardcoded variable with known safe content | Not needed |
| Input that should be regex syntax | Do not escape |
Sometimes you intentionally want the variable to contain regex syntax:
const pattern = "\\d{3,5}"; // Intended as regex
const regex = new RegExp(pattern);
In that case, you do NOT escape.
FAQ
How do I use a variable inside a regex in JavaScript?
Use new RegExp(variable, "flags"). Escape the variable with string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") to avoid special character issues.
How do I use a variable inside a regex in Python?
Use re.compile(re.escape(variable), flags) or re.search(re.escape(variable), text).
How do I use a variable inside a regex in PHP?
Use preg_quote($variable, $delimiter) and embed it in the pattern string: "/" . preg_quote($var, "/") . "/".
What is re.escape() in Python?
re.escape() escapes all special regex characters in a string so it can be used safely in a pattern.
Can I escape regex in JavaScript?
JavaScript does not have a built-in RegExp.escape(), but you can use:
string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
What happens if I do not escape user input?
Special characters in the input will be interpreted as regex syntax, causing incorrect matches and potential security vulnerabilities.
Can I build a regex from a variable using a regex literal?
No. Regex literals in JavaScript (/pattern/) are static. Use new RegExp() for dynamic patterns.
Final Thoughts
Using variables in regex patterns is something every developer eventually needs to do.
The pattern is always the same:
- Escape the input for special regex characters
- Build the pattern using
new RegExp()(JS),re.compile()(Python), orpreg_quote()(PHP) - Test against edge cases that include regex special characters
Most regex-related bugs in production come from forgetting step 1. It is easy to miss because test data rarely includes dots, parentheses, or backslashes. Real-world data always does.
Build the escaping habit early, and dynamic regex patterns will stop surprising you.
If you want to test how dynamic patterns behave with different inputs, the Regex Tester makes it easy to experiment interactively.
You may also find these related developer tools useful: