Last week I was debugging a CloudFront log parser and pasted a chunk of raw access logs into Regex101. Mid-keystroke, I realized those logs contained client IPs, user agents, and request paths from production. All of it, shipped off to someone else’s server for “processing.”
That’s the moment I decided to build my own regex tester.
The Problem with Existing Regex Testers
I looked at three tools I’ve used for years:
Regex101 is the gold standard. Pattern explanations, debugger, community library — it’s feature-rich. But it sends every keystroke to their backend. Their privacy policy says they store patterns and test strings. If you’re testing regex against production data, config files, or anything containing tokens and IPs, that’s a problem.
RegExr has a solid educational angle with the animated railroad diagrams. But the interface feels like 2015, and there’s no way to test multiple strings against the same pattern without copy-pasting repeatedly.
Various Chrome extensions promise offline regex testing, but they request permissions to read all your browser data. I’m not trading one privacy concern for a worse one.
What none of them do: let you define a set of test cases (this string SHOULD match, this one SHOULDN’T) and run them all at once. If you write regex for input validation, URL routing, or log parsing, you need exactly that.
What I Built
RegexLab is a single HTML file. No build step, no npm install, no backend. Open it in a browser and it works — including offline, since it registers a service worker.
Three modes:
Match mode highlights every match in real-time as you type. Capture groups show up color-coded below the result. If your pattern has named groups or numbered captures, you see exactly what each group caught.
Replace mode gives you a live preview of string replacement. Type your replacement pattern (with $1, $2 backreferences) and see the output update instantly. I use this constantly for log reformatting and sed-style transforms.
Multi-test mode is the feature I actually wanted. Add as many test cases as you need. Mark each one as “should match” or “should not match.” Run them all against your pattern and get a pass/fail report. Green checkmark or red X, instantly.
This is what makes RegexLab different from Regex101. When I’m writing a URL validation pattern, I want to throw 15 different URLs at it — valid ones, edge cases with ports and fragments, obviously invalid ones — and see them all pass or fail in one view. No scrolling, no re-running.
How It Works Under the Hood
The entire app is ~30KB of HTML, CSS, and JavaScript. No frameworks, no dependencies. Here’s what’s happening technically:
Pattern compilation: Every keystroke triggers a debounced (80ms) recompile. The regex is compiled with new RegExp(pattern, flags) inside a try/catch. Invalid patterns show the error message directly — no cryptic “SyntaxError,” just the relevant part of the browser’s error string.
Match highlighting: I use RegExp.exec() in a loop with the global flag to find every match with its index position. Then I build highlighted HTML by slicing the original string at match boundaries and wrapping matches in <span class="hl"> tags. A safety counter at 10,000 prevents infinite loops from zero-length matches (a real hazard with patterns like .*).
// Simplified version of the match loop
const rxCopy = new RegExp(rx.source, rx.flags);
let safety = 0;
while ((m = rxCopy.exec(text)) !== null && safety < 10000) {
matches.push({ start: m.index, end: m.index + m[0].length });
if (m[0].length === 0) rxCopy.lastIndex++;
safety++;
}
That lastIndex++ on zero-length matches is important. Without it, a pattern like /a*/g will match the empty string forever at the same position. Every regex tutorial skips this, and then people wonder why their browser tab freezes.
Capture groups: When exec() returns an array with more than one element, elements at index 1+ are capture groups. I color-code them with four rotating colors (amber, pink, cyan, purple) and display them below the match result.
Flag toggles: The flag buttons sync bidirectionally with the text input. Click a button, the text field updates. Type in the text field, the buttons update. I store flags as a simple string ("gim") and reconstruct it from button state on each click.
State persistence: Everything saves to localStorage every 2 seconds — pattern, flags, test string, replacement, and all test cases. Reload the page and you’re right where you left off. The service worker caches the HTML for offline use.
Common patterns library: 25 pre-built patterns for emails, URLs, IPs, dates, UUIDs, credit cards, semantic versions, and more. Click one to load it. Searchable. I pulled these from my own .bashrc aliases and validation functions I’ve written over the years.
Design Decisions
Dark mode by default via prefers-color-scheme. Most developers use dark themes. The light mode is there for the four people who don’t.
Monospace everywhere that matters. Pattern input, test strings, results — all in SF Mono / Cascadia Code / Fira Code. Proportional fonts in regex testing are a war crime.
No syntax highlighting in the pattern input. I considered it, but colored brackets and escaped characters inside an input field add complexity without much benefit. The error message and match highlighting already tell you if your pattern is right.
Touch targets are 44px minimum. The flag toggle buttons, tab buttons, and action buttons all meet Apple’s HIG recommendation. I tested at 320px viewport width on my phone and everything still works.
Real Use Cases
Log parsing: I parse nginx access logs daily. A pattern like (\d+\.\d+\.\d+\.\d+).*?"(GET|POST)\s+([^"]+)"\s+(\d{3}) pulls IP, method, path, and status code. Multi-test mode lets me throw 10 sample log lines at it to make sure edge cases (HTTP/2 requests, URLs with quotes) don’t break it.
Input validation: Building a form? Test your email/phone/date regex against a list of valid and invalid inputs in one shot. Way faster than manually testing each one.
Search and replace: Reformatting dates from MM/DD/YYYY to YYYY-MM-DD? The replace mode with $3-$1-$2 backreferences shows you the result instantly.
Teaching: The pattern library doubles as a learning resource. Click “Email” or “UUID” and see a production-quality regex with its flags and description. Better than Stack Overflow answers from 2012.
Try It
It’s live at regexlab.orthogonal.info. Works offline after the first visit. Install it as a PWA if you want it in your dock.
If you want more tools like this — HashForge for hashing, JSON Forge for formatting JSON, QuickShrink for image compression — they’re all at apps.orthogonal.info. Same principle: single HTML file, zero dependencies, your data stays in your browser.
Full disclosure: Mastering Regular Expressions by Jeffrey Friedl is the book that made regex click for me back in college. If you’re still guessing at lookaheads and backreferences, it’s worth the read. Regular Expressions Cookbook by Goyvaerts and Levithan is also solid if you want recipes rather than theory. And if you’re doing a lot of text processing, a good mechanical keyboard makes the difference when you’re typing backslashes all day.
📧 Get weekly insights on security, trading, and tech. No spam, unsubscribe anytime.
Leave a Reply