\K — keep everything before this point out of the match¶
One line: \K resets the start of the reported match to the current position, so foo\Kbar matches bar only after checking that foo came first — a lookbehind with no width limit — in Perl, PCRE2 and Ruby; Python, Java, Go and both Rust crates refuse it, and JavaScript reads it as the letter K.
Level: reference · one construct, eight engines
What it means¶
The pattern consumes foo; the match begins after it. That is different from (?<=foo)bar, which never consumes foo, in two ways that matter:
- No width limit.
(?<=\w+\s)is refused by every engine with a fixed-width or bounded rule;\w+\s\Kis fine, because it is ordinary matching followed by a reset. - In a replacement, the consumed text is left alone.
s/foo\Kbar/X/producesfooX. Thefoowas part of what the engine walked over, and it is not part of what gets replaced.
The price is that the consumed part is really consumed: a global match continues after it, which is what you want for foo but not for a pattern that needs to re-examine that text.
Measured¶
Verified output of kw_keep_out_sh.sh — regenerated by tools/run_examples.py, never hand-typed.
construct python perl node ruby java go rust fancy
match after \K - bar no bar - - - bar
replace after \K - fooX no fooX - - - fooX
\K in JavaScript - no aKb no - - - no
Reading the table¶
- Row 1.
foo\Kbaronfoobarreportsbarin Perl, Ruby andfancy-regex. Python, Java, Go and Rust'sregexrefuse the escape — Rust's parser has no\K, andfancy-regexadds it on top. - Row 2. Replacing the match with
XgivesfooXin the same three engines: the reset also decides what a substitution touches. - Row 3. JavaScript compiled
a\Kband matchedaKb. There is no\Kthere, and no error either.
The trap¶
Only JavaScript's row 3 — and the portability question. \K is a PCRE-family feature that Ruby adopted; if a pattern using it must also run in Python or Java, the equivalent is a capturing group and group(1), or a lookbehind where the width allows one.
Where it is idiomatic: PCRE2, so pcre2grep -o 'key=\K\w+' and ABAP's PCRE addition; and grep -oP, which is PCRE2 with GNU grep's face.
Where it is measured in depth¶
- Lookahead and lookbehind — the width rules
\Ksidesteps.
See also¶
- Lookbehind
(?<=…)— what\Kreplaces. - Capturing group — what replaces
\Kwhere it is missing. - Command-line tools —
grep -oPandpcre2grep -o.