Regex Match Everything Between Two Characters (2026 Guide)
To match text between two characters in regex, use a lazy quantifier with capture groups \[(.*?)\] or lookarounds (?<=\[).*?(?=\]). The lazy quantifier .*? stops at the first closing character, preventing greedy matching errors that consume the entire string.
👉 Test these exact patterns against your own text instantly using our free Regex Tester
The Quick Answer: Copy These Patterns
Use these optimized patterns for the most common extraction tasks. We provide both the Capture Group version (which includes the boundaries in the full match) and the Lookaround version (which isolates only the inner text at the engine level).
| Target | Capture Group Method | Lookaround Method (Advanced) |
|---|---|---|
| Double Quotes | "(.*?)" | (?<=")[^"]*(?=") |
| Square Brackets | \[(.*?)\] | (?<=\[)[^\]]*(?=\]) |
| Parentheses | \((.*?)\) | (?<=\()[^\)]*(?=\)) |
| HTML / XML Tags | <div>(.*?)<\/div> | (?<=<div>).*?(?=<\/div>) |
Note: For maximum efficiency, replace .*? with a negated character class like [^"]* as shown in the Lookaround column.
The Fatal Flaw: Greedy vs. Lazy Matching
The most common failure in text extraction is "Greedy" behavior. Quantifiers like * (zero or more) and + (one or more) are greedy by default, meaning they consume as much input as possible.
The "Multiple Sets" Failure
If your string contains multiple instances of the same boundary, a greedy pattern will fail.
- String:
"Value A" and "Value B" - Greedy Pattern:
".*" - Incorrect Result:
"Value A" and "Value B"(Matches from the first quote to the very last quote).
The Solution: Lazy Matching (*?)
By adding a ? after the quantifier, you make it "Lazy." This instructs the engine to match the minimum number of characters necessary, halting at the first closing boundary.
- Lazy Pattern:
".*?" - Correct Result:
"Value A"
Before deploying complex patterns, validate your logic with our Regex Tester to avoid production downtime.
Method 1: Using Capture Groups (...)
Capturing groups are the primary mechanism for isolating a specific portion of a match. Placing parentheses around the inner pattern creates a "Capture Group 1" that you can recall in your code.
- Pattern:
\[(.*?)\] - Full Match (Index 0):
[ inner text ] - Group 1 (Index 1):
inner text
If you are using regex to parse JSON, stop immediately. Regex is prone to failure with nested structures. Use a real parser or our JSON Formatter to handle structured data safely.
Method 2: Using Lookarounds (Advanced)
Lookaround assertions are "Zero-Width Assertions." They match a specific position in the text without "consuming" the characters. This allows you to extract text between boundaries without including the boundaries in the final match result.
- Positive Lookbehind (
(?<=...)): Asserts that the current position is preceded by a specific pattern. - Positive Lookahead (
(?=...)): Asserts that the current position is followed by a specific pattern.
Example Pattern: (?<=\[)[^\]]*(?=\])
This asserts a [ exists before the match and a ] exists after it, but only returns what is inside the brackets.
Code Examples: JavaScript, Python, and PHP
JavaScript
const str = "Extract [this] data";
const match = str.match(/(?<=\[).*?(?=\])/g);
console.log(match[0]); // "this"
Python
import re
str = "Extract [this] data"
result = re.findall(r'\[(.*?)\]', str)
print(result[0]) # "this"
PHP
$str = "Extract [this] data";
preg_match('/(?<=\[).*?(?=\])/', $str, $matches);
echo $matches[0]; // "this"
Performance: Preventing Catastrophic Backtracking
Inefficient patterns can lead to Catastrophic Backtracking, where the engine attempts an exponential number of combinations (up to $2^$) on a failing match. This can hang your server and consume 100% CPU.
Senior Engineer Best Practices:
- Be Specific: Use negated character classes like
[^"]*instead of the wildcard.. - Avoid Nested Quantifiers: Never use patterns like
(a+)*. - Use Non-Capturing Groups: Use
(?:...)if you don't need to save the match to memory, reducing overhead.
FAQ
How to extract text between quotes in regex?
Use the lookaround pattern (?<=")[^"]*(?=") for clean extraction, or the capture group pattern "(.*?)" and access index 1 of the result array.
What is a positive lookahead?
A positive lookahead (?=...) is a zero-width assertion that ensures a specific pattern follows the current position without including that pattern in the final match.
Why is my regex matching the whole string instead of just between brackets?
Your pattern is likely using a "Greedy" quantifier like .*. Switch to a "Lazy" quantifier .*? or a negated character class [^\]]* to stop at the first closing bracket.