I'm trying to split up a string into two parts using regex. The string is formatted as follows:
text to extract<number>
I've been using (.*?)<
and <(.*?)>
which work fine but after reading into regex a little, I've just started to wonder why I need the ?
in the expressions. I've only done it like that after finding them through this site so I'm not exactly sure what the difference is.
Repetition in regex by default is greedy: they try to match as many reps as possible, and when this doesn't work and they have to backtrack, they try to match one fewer rep at a time, until a match of the whole pattern is found. As a result, when a match finally happens, a greedy repetition would match as many reps as possible.
The ?
as a repetition quantifier changes this behavior into non-greedy, also called reluctant (in e.g. Java) (and sometimes "lazy"). In contrast, this repetition will first try to match as few reps as possible, and when this doesn't work and they have to backtrack, they start matching one more rept a time. As a result, when a match finally happens, a reluctant repetition would match as few reps as possible.
Let's compare these two patterns: A.*Z
and A.*?Z
.
Given the following input:
eeeAiiZuuuuAoooZeeee
The patterns yield the following matches:
A.*Z
yields 1 match: AiiZuuuuAoooZ
(see on rubular.com)A.*?Z
yields 2 matches: AiiZ
and AoooZ
(see on rubular.com)Let's first focus on what A.*Z
does. When it matched the first A
, the .*
, being greedy, first tries to match as many .
as possible.
eeeAiiZuuuuAoooZeeee
\_______________/
A.* matched, Z can't match
Since the Z
doesn't match, the engine backtracks, and .*
must then match one fewer .
:
eeeAiiZuuuuAoooZeeee
\______________/
A.* matched, Z still can't match
This happens a few more times, until finally we come to this:
eeeAiiZuuuuAoooZeeee
\__________/
A.* matched, Z can now match
Now Z
can match, so the overall pattern matches:
eeeAiiZuuuuAoooZeeee
\___________/
A.*Z matched
By contrast, the reluctant repetition in A.*?Z
first matches as few .
as possible, and then taking more .
as necessary. This explains why it finds two matches in the input.
Here's a visual representation of what the two patterns matched:
eeeAiiZuuuuAoooZeeee
\__/r \___/r r = reluctant
\____g____/ g = greedy
In many applications, the two matches in the above input is what is desired, thus a reluctant .*?
is used instead of the greedy .*
to prevent overmatching. For this particular pattern, however, there is a better alternative, using negated character class.
The pattern A[^Z]*Z
also finds the same two matches as the A.*?Z
pattern for the above input (as seen on ideone.com). [^Z]
is what is called a negated character class: it matches anything but Z
.
The main difference between the two patterns is in performance: being more strict, the negated character class can only match one way for a given input. It doesn't matter if you use greedy or reluctant modifier for this pattern. In fact, in some flavors, you can do even better and use what is called possessive quantifier, which doesn't backtrack at all.
This example should be illustrative: it shows how the greedy, reluctant, and negated character class patterns match differently given the same input.
eeAiiZooAuuZZeeeZZfff
These are the matches for the above input:
A[^Z]*ZZ
yields 1 match: AuuZZ
(as seen on ideone.com)A.*?ZZ
yields 1 match: AiiZooAuuZZ
(as seen on ideone.com)A.*ZZ
yields 1 match: AiiZooAuuZZeeeZZ
(as seen on ideone.com)Here's a visual representation of what they matched:
___n
/ \ n = negated character class
eeAiiZooAuuZZeeeZZfff r = reluctant
\_________/r / g = greedy
\____________/g
These are links to questions and answers on stackoverflow that cover some topics that may be of interest.