\A, \z and \Z — the anchors that mean what ^ and $ are assumed to mean¶
One line: \A is the start of the subject and \z its true end in every engine that has them; \Z is Perl's "end, or before a final newline" in Perl, Ruby, Java and PCRE2 — and in Python \Z means \z, JavaScript has none of the three, and Go and Rust have \A and \z but no \Z.
Level: reference · one construct, eight engines
What it means¶
| Escape | Meaning | Python | Perl / PCRE2 / Ruby / Java | JavaScript | Go / Rust regex |
|---|---|---|---|---|---|
\A |
start of subject, never a line | yes | yes | no — identity escape, matches A |
yes |
\z |
end of subject, nothing after | 3.14+ only | yes | no — matches z |
yes |
\Z |
end, or before one final newline | means \z |
yes | no — matches Z |
refused |
Two collisions live in that table. Python's \Z is spelled like Perl's \Z and means Perl's \z, so a pattern moved between the two changes whether a trailing newline is accepted. And JavaScript accepts all three spellings as ordinary letters, so nothing fails until a subject happens to contain a capital A.
Measured¶
Verified output of kw_start_and_end_of_subject_sh.sh — regenerated by tools/run_examples.py, never hand-typed.
construct python perl node ruby java go rust fancy
\A start a a no a a a a a
\A after a newline no no no no no no no no
\A in JavaScript no no Aa no no no no no
\A with the u flag no no - no no no no no
\z end - a no a a a a a
\z before final newline - no no no no no no no
\Z before final newline no a no a a - - a
\Z before middle newline no no no no no - - no
\Z in JavaScript no no aZ no no - - no
Reading the table¶
- Rows 1–2,
\A. Every engine that has it agrees: match at offset 0, and not after a newline. Node'snoin row 1 is the wrong kind of no — row 3 shows\Aamatching the textAa, and row 4 shows theuflag turning that into a refusal. Underu, JavaScript rejects escapes it does not define, which is the kinder failure; without it, they are letters. - Rows 5–6,
\z. The true end. Python's column is-because the probe runs Python 3.12, which does not have\z; 3.14 does. Write\Zin Python and it means this. - Rows 7–9,
\Z. Perl, Ruby, Java andfancy-regexstep over one final newline (afora\n) and not a middle one (nofora\nb). Python saysnofora\n, because its\Zis the true end. Go and Rust'sregexrefuse\Zoutright rather than reinterpret it — a compile error, which is the good outcome. Node matchesaZ.
The trap¶
Porting a validator. A Perl \A\d+\Z accepts "42\n"; the same characters in Python reject it; in JavaScript they match A42Z. The three engines agree about nothing here except that the pattern compiles.
The portable spelling is \A…\z — true start, true end — in every engine that has both, and in JavaScript ^…$ without the m flag, which is the only case where JavaScript's plain anchors are the strict ones. Or skip the anchors and use the whole-string call the language provides.
Where it is measured in depth¶
$is not the end of the string — the lesson, with the Python 3.14\zreal run and every engine'sfullmatchequivalent.
See also¶
^·$— the anchors these replace.\b·\G— the other zero-width positions.- Validating input · Portability between engines.