Skip to content

\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's no in row 1 is the wrong kind of no — row 3 shows \Aa matching the text Aa, and row 4 shows the u flag turning that into a refusal. Under u, 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 \Z in Python and it means this.
  • Rows 7–9, \Z. Perl, Ruby, Java and fancy-regex step over one final newline (a for a\n) and not a middle one (no for a\nb). Python says no for a\n, because its \Z is the true end. Go and Rust's regex refuse \Z outright rather than reinterpret it — a compile error, which is the good outcome. Node matches aZ.

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

See also