Regex cheat sheet: Java vs JavaScript
The regex differences that break patterns when you move between the browser and the JVM. Filter the table by keyword.
| What | Java | JavaScript | Note |
|---|---|---|---|
| Named group | (?<year>\d{4}) | (?<year>\d{4}) | Same syntax. Names must be alphanumeric in Java (no underscores). |
| Named group in replacement | ${year} | $<year> | Java uses ${name}, JavaScript uses $<name>. |
| Numbered group in replacement | $1 | $1 | Same. Java's appendReplacement treats a backslash as an escape. |
| Backreference in pattern | \1 or \k<name> | \1 or \k<name> | Same. |
| Inline flags | (?i) (?s) (?m) (?x) | not supported (use /i /s /m flags) | Java accepts flags inside the pattern, and scoped forms like (?i:abc). |
| Case-insensitive | Pattern.CASE_INSENSITIVE | /i | Add UNICODE_CASE in Java for non-ASCII letters. |
| Dot matches newline | Pattern.DOTALL or (?s) | /s | |
| Multiline anchors | Pattern.MULTILINE or (?m) | /m | ^ and $ match at line breaks. |
| Start / end of whole input | \A \z \Z | no equivalent (use ^ and $ without /m) | \z is the very end; \Z allows a final line break. |
| Whole-string match | matcher.matches() | /^...$/.test(s) | Java matches() must match the entire string; find() searches. |
| Unicode letters | \p{L} | \p{L} with the u flag | JavaScript needs /u (or /v) for \p{...}. |
| POSIX classes | \p{Alpha} \p{Digit} \p{Punct} | not supported | Java POSIX classes are ASCII-only unless UNICODE_CHARACTER_CLASS is set. |
| Possessive quantifier | a*+ a++ a?+ | not supported | Prevents backtracking. Useful against catastrophic backtracking. |
| Atomic group | (?>...) | not supported | |
| Lookahead | (?=...) (?!...) | (?=...) (?!...) | Same. |
| Lookbehind | (?<=...) (?<!...) bounded length | (?<=...) (?<!...) any length | JavaScript allows variable-length lookbehind; Java needs an upper bound. |
| Literal text | \Q...\E or Pattern.quote(s) | escape each special character | |
| Escape in source code | "\\d+" (double backslash) | /\d+/ or new RegExp("\\d+") | In a Java string every regex backslash is doubled. Text blocks do not remove this. |
| Unicode code point | \x{1F600} or \uD83D\uDE00 | \u{1F600} with u flag | |
| Horizontal whitespace | \h | no equivalent | Java also has \R (any line break) and \v (vertical whitespace). |
| Word boundary | \b | \b | Behaviour with accented letters differs between engines and versions. Test with real data. |
| Global matching | while (m.find()) | /g with matchAll() | |
| Split with limit | s.split(re, -1) | s.split(re) | Java drops trailing empty strings unless the limit is negative. |
Java regex versus JavaScript regex
Java's java.util.regex and JavaScript's RegExp are close cousins, which makes the differences more annoying: a pattern you tested in the browser console fails in your Spring service, or the other way round. Most of the core syntax (character classes, quantifiers, groups, alternation, lookahead) is identical. The differences cluster in a few places: how flags are written, how replacements refer to groups, what lookbehind allows, which anchors exist, and what Java adds on top (possessive quantifiers, atomic groups, \Q...\E quoting and POSIX classes).
The table lists the differences that actually cause bugs. Type in the search box to filter, for example "lookbehind" or "flag".
Three habits that save time
- Write the pattern in a regex tester first, then paste it into Java as an escaped string, instead of escaping by hand.
- Decide between
matches()andfind()on purpose. Validation usually wantsmatches(); searching wantsfind(). - Compile a pattern once into a static
Patternconstant.String.matchescompiles on every call.
The sheet reflects the documented behaviour of the current JDK and ECMAScript; older JDKs and JavaScript engines may differ in details. Everything is static and works offline.
Frequently asked questions
Why does my JavaScript regex not work in Java?
The most common reasons are that the backslashes were not doubled in the Java string, you used a JavaScript-only flag syntax, or Java's matches() needed the entire input to match. Variable-length lookbehind also works in JavaScript but not in Java.
Does Java support named groups?
Yes, since Java 7: (?<name>...), read with matcher.group("name"). Names may contain only letters and digits.
What is catastrophic backtracking?
A pattern such as (a+)+b can take exponential time on input that almost matches. Use possessive quantifiers or atomic groups in Java to prevent it, or rewrite the pattern.
How do I test a Java regex safely?
Use the regex tester on this site, which copies the pattern as an escaped Java string so you do not lose backslashes.