The issue you're experiencing is due to the nature of backtracking in regex. The regex engine is parsing the string at each given position therein, and as such, will attempt every option of the pattern until it either matches or fails at that position. If it matches, it will consume those characters and if it fails it will continue to the next position until the end of the string is met.
The keyword here is backtracks. I think Microsoft's documentation does a great job of defining this term (I've bolded the important section):
Backtracking occurs when a regular expression pattern contains
optional quantifiers or alternation constructs, and the regular
expression engine returns to a previous saved state to continue its
search for a match. Backtracking is central to the power of regular
expressions; it makes it possible for expressions to be powerful and
flexible, and to match very complex patterns. At the same time, this
power comes at a cost. Backtracking is often the single most important
factor that affects the performance of the regular expression engine.
Fortunately, the developer has control over the behavior of the
regular expression engine and how it uses backtracking. This topic
explains how backtracking works and how it can be controlled.
The regex engine backtracks to a previous saved state. It cannot forward track to a future saved state, although that would be pretty neat! Since you've specified that your match should end with at
(the lazy quantifier precedes it), it will exhaust every regex option until \w{1,2}
ending in at
proves true.
How can you get around this? Well, the easiest way is probably to use a capture group:
See regex in use here
\w*(\w{1,2}?at)
\w*(\w{1,2}at) # yields same results as above (but in more steps)
\w*(\wat) # yields same results as above (faster method)
\wat # yields same results as above (fastest method)
\b\w{1,2}at\b # perhaps this is what OP is after?
\w*
Matches any word character any number of times. This is a fix to allow us to simulate forward tracking (this is not a proper term, just used in the context of the rest of my answer above). It will match as many characters as possible and work its way backwards until a match occurs.
- The rest of the pattern the OP already had. In fact,
\w{2}
will never be met since \w
will always only be met once (since the \w*
token is greedy), therefore \wat
can be used instead \w*(\wat)
. Perhaps the OP intended to use anchors such as \b
in the regex: \b\w{1,2}at\b
? This doesn't differ from the original nature of the OP's regex either since making the quantifier lazy would have theoretically yielded the same results in the context of forward tracking (one match of \w
would have satisfied \w{1,2}?
, thus \w{2}
would never be reached).