Greedy and lazy quantifiers in regular expressions

An attempt at being thorough and complete. Mainly for my own benefit.
Most pages about regexes mention + and * as the greedy ones and +? and *? as their lazy equivalents. However, there are more combinations of quantifiers that can be distinguished into lazy and greedy variants. So here we go.

greedy lazy example
+ +? X+ matches all X’s in XXXYYY
X+? matches the first X in XXXYYY
This is rather straightforward: + matches one or more of the preceding, so X+ matches all X’s and X+? matches just one X.
JavaScript example:
'XXXYYY'.replace(/X+/, 'o') results in oYYY
'XXXYYY'.replace(/X+?/, 'o') results in oXXYYY
greedy lazy example
* *? X* matches all X’s in XXXYYY
X*? matches the empty string at the start of XXXYYY
Pretty much the same as above: * matches zero or more of the preceding, so X* matches all X’s and X*? matches just zero X’s, that is, nothing.
JavaScript example:
'XXXYYY'.replace(/X*/, 'o') results in oYYY
'XXXYYY'.replace(/X*?/, 'o') results in oXXXYYY
greedy lazy example
? ?? X? matches the first X in XXXYYY
X?? matches the empty string at the start of XXXYYY
? matches zero or one of the preceding, so X? matches the first X and X?? matches no X, or nothing.
JavaScript example:
'XXXYYY'.replace(/X?/, 'o') results in oXXYYY
'XXXYYY'.replace(/X??/, 'o') results in oXXXYYY
greedy lazy example
{n,m} {n,m}? X{2,3} matches the first three X’s in XXXYYY
X{2,3}? matches the first two X’s in XXXYYY
This may not be as familiar to some, but it works in the same way: X{n,m} matches at least n and at most m X’s, so X{2,3} matches three X’s (if possible), while X{2,3}? matches only two (if possible).
JavaScript example:
'XXXYYY'.replace(/X{2,3}/, 'o') results in oYYY
'XXXYYY'.replace(/X{2,3}?/, 'o') results in oXYYY
greedy lazy example
.. | | .. X| matches the first X in XXXYYY
|X matches the empty string at the start of XXXYYY
And somewhat unexpected maybe, but the logical “or” operator can be used with the empty string as one of its choices, and the result depends on whether you put the empty string first or last; it checks from left to right. So X| matches an X (if there is one), and |X matches the empty string.
JavaScript example:
'XXXYYY'.replace(/X|/, 'o') results in oXXYYY
'XXXYYY'.replace(/|X/, 'o') results in oXXXYYY

That’s all the ones I can think of. If anybody knows of more constructs that can be used in both a greedy and a lazy manner, comment below and I’ll update this.