The fact that lookaround is zero-length automatically makes it atomic. As soon as the lookaround condition is satisfied, the regex engine forgets about everything inside the lookaround. It will not backtrack inside the lookaround to try different permutations.
The only situation in which this makes any difference is when you use capturing groups inside the lookaround. Since the regex engine does not backtrack into the lookaround, it will not try different permutations of the capturing groups.
For this reason, the regex (?=(\d+))\w+\1 never matches 123x12. First the lookaround captures 123 into \1. \w+ then matches the whole string and backtracks until it matches only 1. Finally, \w+ fails since \1 cannot be matched at any position. Now, the regex engine has nothing to backtrack to, and the overall regex fails. The backtracking steps created by \d+ have been discarded. It never gets to the point where the lookahead captures only 12.
Obviously, the regex engine does try further positions in the string. If we change the subject string, the regex (?=(\d+))\w+\1 does match 56x56 in 456x56.
Positive lookbehind, however, is not atomic in Python, Ruby, and Boost. It was not atomic in Perl 5.34 and prior either. These flavors implement a lookbehind that contains alternation as a separate lookbehind for each alternative. Backtracking causes these flavors to try the other alternatives in case of positive lookbehind. Negative lookbehind is still atomic, effectively, because all permutations need to be tried to determine that negative lookbehind can’t match its contents and thus succeed. Lookahead is atomic in all regex flavors discussed in this tutorial.
If you don’t use capturing groups inside lookaround, then all this doesn’t matter. Either the lookaround condition can be satisfied or it cannot be. In how many ways it can be satisfied is irrelevant.
PCRE2 10.34 invented new syntax for non-atomic positive lookaround. The syntax is self-explanatory, with long and short variants: (*non_atomic_positive_lookahead:regex), (*napla:regex), (*non_atomic_positive_lookbehind:regex), and (*naplb:regex). It works just like regular positive lookaround and has the same limitations for lookbehind. Non-atomic positive lookbehind must still be of finite length.
PCRE2 10.35 invented yet another kind of syntax for the same thing. (?*regex) is non-atomic positive lookahead. (?<*regex) is non-atomic positive lookbehind.
PHP and R also support non-atomic positive lookaround as they are based on PCRE2. PHP supports the self-explanatory syntax since version 7.4.6 and the ?* syntax since version 7.4.12. R supports both starting with version 4.2.0.
So while (?=(\d+))\w+\1 still never matches 123x12 in PCRE2, (?*(\d+))\w+\1 does match 123x12. The initial matching process is the same. The lookaround captures 123 into \1. \w+ then matches the whole string and then backtracks all the way to find out that \1 cannot be matched at any position. But this time around, the regex engine does have something to backtrack to. \d+ can reduce its match to 12 which is then captured by the group. The lookaround succeeds again. \w+ again matches the whole string. \1 fails and backtracking forces \w+ reduce its match. After giving up 2 characters, \1 can match the second 12 in the string. An overall match is found.
Of course, this particular regex could have been written as (\d+)\w*\1 to achieve the same result with any regex flavor that supports backreferences. Real-world benefits of non-atomic lookaround are limited.
There is no non-atomic negative lookaround. Negative lookaround must always try all permutations to ensure none of them can match before the negative lookaround can succeed. So there are never any backtracking positions to preserve or discard after matching negative lookaround.
| Quick Start | Tutorial | Search & Replace | Tools & Languages | Examples | Reference |
| Introduction | Table of Contents | Special Characters | Non-Printable Characters | Regex Engine Internals | Character Classes | Character Class Subtraction | Character Class Intersection | Shorthand Character Classes | Dot | Anchors | Word Boundaries | Alternation | Optional Items | Repetition | Grouping & Capturing | Backreferences | Backreferences, part 2 | Named Groups | Relative Backreferences | Branch Reset Groups | Free-Spacing & Comments | Unicode Characters & Properties | Mode Modifiers | Atomic Grouping | Possessive Quantifiers | Lookahead & Lookbehind | Lookaround, part 2 | Lookbehind Limitations | (Non-)Atomic Lookaround | Keep Text out of The Match | Conditionals | Balancing Groups | Recursion and Subroutines | POSIX Bracket Expressions | Zero-Length Matches | Continuing Matches | Backtracking Control Verbs | Control Verb Arguments |
Page URL: https://www.regular-expressions.info/lookaroundatomic.html
Page last updated: 17 June 2025
Site last updated: 29 October 2025
Copyright © 2003-2025 Jan Goyvaerts. All rights reserved.