POSIX specifies that ERE chooses the leftmost longest match (see regex(7), or re_format(7) on BSD):

In the event that an RE could match more than one substring of a given string, the RE matches the one starting earliest in the string. If the RE could match more than one substring starting at that point, it matches the longest.

“Earliest” (i.e. “leftmost”) is consistent with PCRE, but “longest” is not. To illustrate the difference, consider the pattern /a?(ab)?/ and the string "ab". Note that the possible matches are "a" and "ab".

PCRE matches "a": /a?/ matches "a", and then /(ab)?/ matches the empty string. grep -P, perl, and python all exhibit this behavior:

$ echo ab | grep -oP 'a?(ab)?'
$ echo ab | perl -pe 's/a?(ab)?/c/'
$ python -c 'import re; print re.search(r"a?(ab)?", "ab").group()'

ERE, on the other hand, matches "ab", the longest of the possible matches. grep -E, sed -r, and awk serve as examples of this:

$ echo ab | grep -oE 'a?(ab)?'
$ echo ab | sed -r 's/a?(ab)?/c/'
$ awk 'BEGIN { s = "ab"; sub(/a?(ab)?/, "c", s); print s }'

Interestingly, vim matches "a" (using the pattern /\va?(ab)?/).