Guide
How to Test Regular Expressions Online
Write and debug regex patterns with live highlighting, match positions, and instant feedback in the browser.
By Sorawi Tools Team · Published July 1, 2026
Why Regular Expressions Demand a Tester
A regular expression is a compact program for matching text, and like any program it is unforgiving: one misplaced metacharacter silently changes what it matches, and a pattern that matches perfectly in your head often fails or matches too much in practice. Reading a pattern like ^(?=.{8,})(?=.*[A-Z])(?=.*d).*$ and predicting what it does is unreliable, which is why every developer who writes regex spends time debugging it. A tester changes the loop. You type a pattern, paste test text, and see exactly which parts light up, where each match starts and ends, and what each capture group contains. That feedback converts regex from guesswork into verification. The stakes are real because regex appears everywhere: validation of emails, phone numbers, and passwords in application code; parsing and extraction in logs and datasets; find-and-replace in editors; filtering in grep and command-line tools; and route matching in web frameworks. A pattern that over-matches can silently accept bad input, and a pattern that under-matches rejects good data and makes users bounce. Testing is not a luxury, it is the normal workflow of writing a correct pattern. The Regex Tester runs entirely in your browser, so you can test patterns against real, possibly sensitive sample data without those samples ever leaving your machine.
Regex Building Blocks You Will Actually Use
A useful pattern is assembled from a small set of building blocks. Literals match themselves: the a in /cat/ matches the letter a. Character classes match one character from a set, so /[0-9]/ matches any digit, /[a-z]/ matches lowercase letters, and a negated class like /[^0-9]/ matches anything that is not a digit. Quantifiers attach to the thing before them: * means zero or more, + means one or more, ? means zero or one, and {2,4} means between two and four. Anchors fix positions: ^ matches the start of the string and $ matches the end, so /^cat$/ matches only the exact word cat. Groups and alternation give you structure: parentheses create capture groups, (?:...) creates a group that does not capture, and | means or, so /gr(a|e)y/ matches both gray and grey. Shortcut escapes keep patterns readable. \d matches any digit, \w matches word characters, \s matches whitespace, and \b matches a word boundary. A concrete example ties it together: the pattern /^[A-Z]{2}d{3}$/ matches a two-letter, three-digit code like AB123 and rejects AB12 and abc123. Escaping is the part that trips people up: a literal dot in a file name must be written \. because an unescaped dot matches any character, and the backslash itself is a literal only when written \\. In the tester you type the pattern as it would appear in code, so the same escaping discipline applies in both places. Building up a pattern in small pieces is the difference between a working expression and a debugging session. Start with the literal text you must match, add one class or quantifier at a time, and test after every addition so you always know which component broke the match. Once the happy path works, add the negative cases: what should be rejected, and whether the pattern accidentally matches a substring it should not. A pattern like /\d{3}/ matches 123 inside the string ABC123, which is correct for extraction but wrong for validation, and that distinction is exactly what anchors exist to control.
Flags: g, i, m, s, and u
Flags change how a pattern behaves globally, and they explain many "why did it match differently" mysteries. The g flag makes matching global, so all matches are found instead of just the first one. The i flag makes matching case-insensitive, so /hello/i matches Hello and HELLO. The m flag turns on multiline mode, which changes ^ and $ so they match at the start and end of every line instead of only the start and end of the whole string; this is the flag you reach for when validating or extracting from multi-line text. The s flag, called dotall, makes the dot match newline characters too, which is essential when a pattern must span multiple lines. The u flag is unicode mode: it treats the text as a sequence of proper code points rather than UTF-16 code units, which matters for emoji and astral-plane characters, and it enables property escapes like \p{L} for any letter. The choice of flags is often the entire difference between a working and a broken pattern. Consider the pattern /^start/m applied to a three-line block: without m it matches nothing, with m it matches the start of every line that begins with the text start. Emoji are the sharpest illustration of the u flag: an emoji like the family symbol is composed of multiple code units, and without u a pattern counting characters will split it apart. Test your pattern with the flags you intend to ship, because a tester with different flags than your production environment can approve a pattern that behaves differently in production. One more flag is worth knowing even though you will rarely set it directly: the d flag requests match indices, which gives you the exact start and end positions of matches and capture groups. Most tools already surface positions through their match table, which is what the Regex Tester does, but if you write code that needs to slice the original string using the matches, the d flag is how you get those offsets programmatically.
How to Test a Pattern with the Regex Tester
Testing a pattern is a tight loop: enter the pattern, paste realistic input, and read the results until the pattern matches exactly what you intend and nothing else.
- 1Open the Regex Tester tool in your browser
- 2Enter your pattern, with or without the surrounding slashes
- 3Select the flags you plan to use, such as g, i, m, s, or u
- 4Paste realistic test text into the input area, including edge cases like empty lines and unusual characters
- 5Review the live highlights and the match table, which lists every match with its start position and length
- 6Inspect the capture groups on each match, then adjust the pattern and retest until it behaves correctly
Common Regex Mistakes and How to Avoid Them
The most common mistake is using a literal dot where you mean a literal dot. The pattern /file.v1/ matches fileXv1 and file-v1 just as happily as file.v1, because the dot matches any character. Escape it: /file\.v1/. The second mistake is greedy quantifiers matching more than intended. The pattern /<b>(.*)<\/b>/ applied to <b>One</b> and <b>Two</b> grabs everything from the first opening tag to the last closing tag in one huge match. The lazy form .*? stops at the first closing tag, which is usually what you want. The third is catastrophic backtracking: nested quantifiers like (a+)+ on a long string of a's followed by a non-matching character can make the engine grind through an exponential number of paths and freeze your page. If a pattern is taking ages, simplify it. Other frequent failures come from anchors and scope. People forget ^ and $ and then wonder why the pattern matches inside a longer string, or they add them and break legitimate matches. Escaping needs change between contexts, and the backslash-vs-string-escape interaction in languages is a classic source of bugs. Above all, never assume a pattern is correct because it matches the happy path. Test it against the inputs you know should fail: empty strings, missing fields, unexpected whitespace, and the trickiest strings you have seen in real data. And resist the temptation to parse HTML with regex; markup with nested tags breaks every hand-rolled pattern, which is a lesson every developer learns exactly once. Match what you can see. A pattern that depends on punctuation you cannot confirm in the sample, such as a specific quote style or a trailing comma, will fail the moment real data omits it. Build the pattern from the smallest stable piece of the string you are looking for, and let the tester show you the borderline cases before real data does it for you.
From Tested Pattern to Production Code
Once a pattern is tested, shipping it is mostly a matter of porting syntax. The Regex Tester uses JavaScript semantics, and most patterns carry across languages cleanly, but the differences matter at the edges. In JavaScript you write a literal like /\d{3}-\d{4}/gm or use the RegExp constructor. In Python you write re.compile(r"\d{3}-\d{4}", re.MULTILINE | re.GLOBAL), where the r prefix prevents backslashes from being eaten by the string parser. In grep you drop the slashes entirely and pass flags like grep -E "\d{3}-\d{4}". The backslash is the friction point everywhere: in a string, a single backslash is often an escape character itself, so you either use raw strings or double the backslashes. Test in the target language after porting, because a pattern that is valid in JavaScript can be rejected by a stricter parser elsewhere. Match the flags to production behavior before you consider the pattern done. If you tested with m but your validation code never sets the multiline flag, the pattern will misbehave in production. Lookbehind assertions and named groups are newer features with uneven support, so check the runtime you are targeting. Finally, test with the actual shape of your data. A log line, a form field, and a config file have different whitespace, line endings, and encodings, and patterns written against idealized examples fail against real input. Build your sample text from real samples, keep the edge cases in the test, and you will ship regex that does what you verified it does. A pattern that passes a tester but was never run against a realistic dataset is a pattern that is still untested; the tester only helps when you feed it the same shape of input your application will actually receive.
A Worked Example: Validating a US Phone Number
A worked example makes the process concrete. Suppose you need to validate a ten-digit US phone number in a web form, and the requirement is to accept the formats people actually type: 5551234567, 555-123-4567, (555) 123-4567, and 555.123.4567, while rejecting everything else. The first attempt /^\d{3}-\d{3}-\d{4}$/ matches only the dashed form, so 5551234567 and the parenthesized version both fail. The next iteration /^\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}$/ moves closer: the \(? makes an opening parenthesis optional, the [\s.-]? allows a space, dot, or dash as a separator, and the final \d{4} captures the last four digits. Test the pattern against the four accepted forms plus the rejects, and each failure teaches you something. The input 555-1234 has too few digits, 555)123-4567 has an unpaired closing parenthesis that the pattern lets through, and 555 12 34567 has a separator in the wrong place. Closing those gaps usually means tightening the alternation or anchoring rather than adding another wildcard. This is exactly where the tester earns its keep. You type the accepted forms and the rejects side by side, and the live highlight and match table show instantly which inputs pass. You also see the capture groups, which matters because a validation pattern often doubles as an extraction pattern, and the group boundaries determine what you can pull out of a successful match. Build the pattern one requirement at a time, verify every format you must accept, verify every format you must reject, and only then move the pattern into production code. The same discipline scales to any structured input, from ZIP codes and credit card numbers to email addresses and ISO dates, and the tester stays useful at every step because the verification loop is the same: adjust, observe, and confirm against the real shapes of your data.
Regex Tester
Test regular expressions against sample text with live highlighting and match details. Perfect for developers.
