Raw strings: Python needs them, JavaScript does not
# Python — without raw string, backslashes need double-escaping:
import re
re.search("\d+", text) # \d is a regex digit, but Python processes \ first
re.search(r"d+", text) # r"..." is a raw string — no Python escape processing
# This is the correct, standard Python regex style
// JavaScript — no raw string concept, always need double backslash:
/d+/.test(text) // regex literal — no extra escaping
new RegExp("\d+").test(text) // string constructor — needs double backslashIn Python, always use raw strings (r"...") for regex patterns. Not doing so is a source of subtle bugs that often work by accident (since "\d" is not a recognized escape sequence in Python and is treated as the literal two characters\ and d, which in a regex matches the same as \d— but this is undefined behavior in strict mode).
Match anchoring: Python's re.match() vs re.fullmatch() vs re.search()
# Python — three different match functions with different anchoring:
import re
re.search(r"d+", "abc123def") # Finds match anywhere: "123"
re.match(r"d+", "abc123def") # Must match at START: None (starts with 'a')
re.match(r"d+", "123abc") # Matches at start, doesn't require full match: "123"
re.fullmatch(r"d+", "123abc") # Must match ENTIRE string: None
re.fullmatch(r"d+", "123") # Full match: "123"
// JavaScript equivalent:
/d+/.test("abc123def") // true — like re.search()
/^d+$/.test("123abc") // false — anchored like re.fullmatch()
/^d+/.test("123abc") // true — anchored at start like re.match()The most common mistake: Python developers use re.match() thinking it validates the entire string, then are surprised when re.match(r"\d+", "123abc")returns a match. Use re.fullmatch() for validation, re.search() for finding patterns in text.
Named groups: different syntax
# Python: (?P<name>...) syntax for named groups
import re
m = re.search(r"(?P<year>d{4})-(?P<month>d{2})", "2026-05")
m.group('year') # "2026"
m.groupdict() # {'year': '2026', 'month': '05'}
// JavaScript (ES2018+): (?<name>...) syntax
const m = "2026-05".match(/(?<year>d{4})-(?<month>d{2})/);
m.groups.year // "2026"
// Python 3.7+ also supports (?<name>...) in some contexts but
// (?P<name>...) is the standard and recommended Python syntaxFinding all matches: re.findall() vs str.matchAll()
# Python:
import re
# No groups — returns list of matched strings:
re.findall(r"d+", "a1 b23 c456") # ["1", "23", "456"]
# One group — returns list of group matches:
re.findall(r"(d+)", "a1 b23 c456") # ["1", "23", "456"] (same here)
# Multiple groups — returns list of tuples:
re.findall(r"([a-z])(d+)", "a1 b23 c456") # [("a","1"), ("b","23"), ("c","456")]
// JavaScript (ES2020+) — matchAll returns an iterator of match objects:
[..."a1 b23 c456".matchAll(/([a-z])(d+)/g)]
.map(m => ({ letter: m[1], num: m[2] }))
// [{letter:"a", num:"1"}, {letter:"b", num:"23"}, {letter:"c", num:"456"}]Flags: mostly equivalent, partly different
# Python flags (passed as second arg to re functions):
re.IGNORECASE (re.I) → /pattern/i in JS
re.MULTILINE (re.M) → /pattern/m in JS
re.DOTALL (re.S) → /pattern/s in JS
re.VERBOSE (re.X) → no JS equivalent (allows whitespace+comments in pattern)
re.UNICODE (re.U) → default in Python 3 (no flag needed)
# Python also allows combining flags:
re.search(r"d+", text, re.IGNORECASE | re.MULTILINE)
// JS uses flag string:
/d+/im
# Python's re.VERBOSE (re.X) is the biggest feature gap:
# It allows multi-line patterns with whitespace and # comments.
# JavaScript has no equivalent — regex literals cannot span lines.
pattern = re.compile(r"""
(d{4}) # year
-
(d{2}) # month
-
(d{2}) # day
""", re.VERBOSE)Python's re.VERBOSEmode is legitimately better for complex patterns — it allows comments directly in the regex. If you write complex patterns in Python, use it. JavaScript's lack of an equivalent is a real shortcoming; the workaround is a comment above the regex.
The practical takeaway
Regex patterns are mostly portable between Python and JavaScript for simple cases. The differences surface in: anchoring behavior (Python's re.match() is not equivalent to a JavaScript anchored pattern), named group syntax ((?P<name>) vs (?<name>)), and how all-matches are returned. The stateful lastIndexbehavior of JavaScript'sg flag has no equivalent in Python. When porting regex-heavy code between languages, test every pattern — do not assume portability.
Test your regex patterns
Regex Tester — test patterns with live highlighting →