Skip to content
100% Client-SideJava (java.util.regex)Dialect-Aware Translation

Java Regex Tester — java.util.regex.Pattern, Translated Live

Write patterns in java.util.regex dialect — POSIX-style \p{Alpha} properties, \Q...\E literal quoting, named groups as (?<host>...) — and the translator expands each to its JavaScript equivalent in real time, showing every rewrite. Constructs Java supports that JavaScript cannot express, like possessive quantifiers, are rejected with the exact reason.

  • Zero upload, ever

    Patterns and test data are evaluated in your browser — connection strings and column values never touch a server.

  • Live translation

    The dialect translator and the match engine recompute on every keystroke, with notices explaining each rewrite.

  • Honest where it matters

    Constructs that cannot be translated faithfully are rejected with a precise reason — never silently mis-matched.

Test string

Matches highlight as you type

Match results

Sandboxed Web Worker

Type a pattern to see live matches.

Java regular expressions, in depth

Engine: java.util.regex.Pattern on the JVM. The tester translates your pattern for live evaluation — these sections document how Java's engine really behaves and where it differs from the evaluation engine.

Pattern and Matcher — the API this tester mirrors

Java regex lives behind two classes: Pattern.compile() turns source text into a compiled pattern, and Matcher walks a subject string. The API's three entry points map directly onto what this tester shows you: matcher.find() is the tester's global mode (each call advances to the next match, like the match table's rows), matcher.matches() requires the entire region to match (that is ^pattern$ here), and matcher.lookingAt() anchors at the start without requiring the end (that is ^pattern alone). If a pattern validates in global mode but your production matches() call returns false, the difference is anchoring — the highlight view shows exactly where the match stopped short of the string end.

Group semantics carry over one-to-one. Java's numbered groups are m.group(1) through m.group(N); named groups — supported since Java 7 — are m.group("name"), and the tester's group panel shows the same names with the same values. The region API (matcher.region(start, end)) has no flag equivalent, but slicing the test string before pasting reproduces it exactly. One Java-only nicety worth knowing when you go back to code: Pattern is immutable and thread-safe, and compile once, reuse across threads is the idiomatic — and safe — pattern.

\p{...} — Java's POSIX shortcuts versus Unicode categories

Java accepts two \p{...} vocabularies that are easy to conflate. The POSIX-inspired shortcuts — \p{Alpha}, \p{Digit}, \p{Alnum}, \p{Upper}, \p{Lower}, \p{Punct}, \p{XDigit} — are ASCII-only by default, matching exactly [A-Za-z] and friends; with Pattern.UNICODE_CHARACTER_CLASS they widen to Unicode. The general-category escapes — \p{L} (letter), \p{N} (number), \p{Lu} (uppercase letter) — are Unicode from the start. The tester expands the ASCII shortcuts to explicit classes (and notes that the UNICODE_CHARACTER_CLASS variant is broader), while general categories pass through with JavaScript's u flag added, since the two engines share that vocabulary.

Java's Is-prefixed block escapes — \p{IsBasicLatin}, \p{IsGreek} — have no reliable JavaScript equivalent: JavaScript exposes scripts (\p{Script=Greek}) and a different block taxonomy, so the translator rejects them with that explanation rather than mapping IsLatin to something approximately similar. If you need script-level matching in portable code, \p{Script=...} works in both Java (as \p{script=Greek}, Java 7+) and JavaScript with u — that is the shared, safe vocabulary.

\Q...\E and the escaping discipline

Java programmers meet \Q...\E through Pattern.quote(): it quotes literal text so metacharacters lose their meaning — invaluable when a user-supplied string must be matched verbatim inside a larger pattern. The translator expands \Q...\E to an explicitly escaped literal, so the quoted region survives translation with its meaning intact, and the notice tells you the expansion happened. In Java code, reach for Pattern.quote() at the boundary where data becomes pattern; here, paste the quoted form and the expansion is done for you.

The escaping discipline around user input is the same in both languages: never interpolate raw input into a pattern, because parentheses, brackets, and backslashes all change meaning. Java's Matcher also offers Matcher.quoteReplacement() for the replacement side — the fix for $ and \ in replacement strings — which maps to JavaScript's replacement-string escaping of $ as $$. Both are small APIs that prevent whole classes of bugs, and both are worth using even when the pattern side feels safe.

Anchors, boundaries, and the possessive wall

Java and JavaScript agree on more anchor semantics than most flavor pairs: \b word boundaries, \B non-boundaries, and lookbehind (Java's must be bounded-length; JavaScript's allows unbounded) all translate by passthrough. The difference concentrates at the string's end: Java's \z is the true absolute end, \Z matches before a final newline, and $ matches before a final newline unless MULTILINE makes it per-line. JavaScript's $ (no m) is Java's \Z exactly, so the translator maps \z and \Z both to $ and attaches the caveat — if you are validating that no trailing newline survives (trimmed fields, tokens), test with the newline present.

The hard wall is possessive quantifiers and atomic groups: a*+, a++, (?>ab) suppress backtracking into the atom, and JavaScript's engine simply cannot express that (the experimental v flag aside). The translator rejects them by name because dropping the + would change match results on crafted input — the exact failure a tester exists to prevent. The standard Java-side alternatives — rewriting with lookahead emulation or bounded alternation — work in both languages, and the ReDoS guard here still catches the catastrophic shapes possessive quantifiers were usually invented to fix.

Java versus the evaluation engine

What translates automatically, what carries a caveat, and what is rejected — construct by construct.

Syntax differences between Java regex and JavaScript RegExp
ConstructJavaThis tester
POSIX \p{...} shortcuts\p{Alpha} etc., ASCII by default; Unicode with UNICODE_CHARACTER_CLASSExpanded to exact ASCII classes; Unicode variant noted
\Q...\ELiteral quoting (also Pattern.quote())Expanded to an explicitly escaped literal
String end\z absolute; \Z before final newline; $ like \Z unless MULTILINE$ maps to \Z behavior — caveat attached
Possessive / atomica*+, a++, (?>...) supported since Java 1.4No equivalent — rejected with the reason
LookbehindMust be finite, bounded lengthAllows unbounded — patterns legal here may fail to compile in Java
Named groups(?<name>...) since Java 7Identical syntax — passes through
Matching modelfind() iterates; matches() requires full matchGlobal mode is find(); ^…$ emulates matches()
Blocks\p{IsBasicLatin} and Is-block escapesNot supported — use \p{Script=...}, shared by both

Java regex cheat sheet

The Java-specific tokens, with the constructs that cannot be translated marked explicitly.

Java regex token cheat sheet
TokenMeaningExample
\p{Alpha}ASCII letter (Java POSIX shortcut)\p{Alpha}+ → Acme
\p{Digit}ASCII digit\p{Digit}{3} → 123
\p{Alnum}ASCII letter or digit\p{Alnum}+ → a1B2
\p{L}Unicode letter (general category)\p{L}+ → naïve
\Q…\EQuote literal text\QC++\E → literal C++
(?<name>…)Named group (Java 7+)(?<host>\w+\.\w+)
\A \z \ZStart / absolute end / end before final newline\A\d+\z
\bWord boundary\bvoid\b → not avoid
a*+Possessive quantifier — not translatableblocked with a reason
(?>ab)Atomic group — not translatableblocked with a reason

Frequently asked questions

Why is my possessive quantifier rejected?

Java's a*+ and (?>...) disable backtracking into the atom — a performance control JavaScript's engine cannot express. Dropping the + or unwrapping the atomic group would leave a pattern that matches differently on crafted input, so the translator refuses with a message saying exactly that. If the possessive quantifier was there to fight catastrophic backtracking, the tester's two-second ReDoS budget will surface whether the non-possessive form is actually safe.

Does \p{Alpha} match Unicode letters here?

Not by default — and that is correct Java behavior. \p{Alpha} is ASCII-only unless the pattern is compiled with Pattern.UNICODE_CHARACTER_CLASS, in which case it widens to Unicode letters. The tester expands \p{Alpha} to its exact ASCII class and attaches a notice about the wider variant. For intentionally Unicode matching, use the general-category escape \p{L} instead: it is Unicode-first in Java and translates here with the u flag added automatically.

How do \z and \Z translate, and why do I care?

Java's \z matches only the true end of input; \Z also matches just before a single trailing newline — and JavaScript's $ (without the m flag) behaves exactly like \Z. The translator maps both to $ and documents the difference in a notice. It matters when validating fields where a trailing newline must not pass: with \z semantics in mind, keep a newline at the end of your test string and check whether the match still extends to it.

Can I test lookbehind that Java would reject?

Possibly, yes — and that is a real fidelity boundary. Java requires lookbehind alternatives to have bounded, computable length; JavaScript accepts unbounded lookbehind like (?<=ab*)c. A pattern using unbounded lookbehind can therefore validate here and still throw when compiled in Java. Keep Java's restriction in mind for lookbehind containing * or +; fixed-length lookbehind like (?<=\$) works identically in both.

How does this tester's output map to Matcher methods?

The match table is matcher.find() in a loop: one row per match, in order, with span offsets like m.start() and m.end(). The named-group panel is m.group("name"); the whole-match row is m.group(). Turning global mode off gives you a single matcher.find() call. matcher.matches() — the full-string variant — is expressed by anchoring with ^ and $, and matcher.lookingAt() by a leading ^ alone.

Is Pattern.quote() the same as \Q...\E?

Pattern.quote("text") returns \Qtext\E — the API method is literally a wrapper around the quoting syntax, with a fallback to escaping when the text contains \E. The tester expands any pasted \Q...\E region to an explicitly escaped literal, so both forms work. The rule it enforces is the one worth internalizing: data interpolated into patterns must be quoted, whether by Pattern.quote(), \Q...\E, or — in your own Java code — by not building patterns from user input at all.