3 options to achieve the same in Regex

I’m trying to write regex that can search for singular and plural forms.

re.search(r'dress(es\b|\b)','dresses')
re.search(r'dress(es)?\b','dresses')
re.search(r'dress[(es)\b]','dresses')

Output

<re.Match object; span=(0, 7), match='dresses'>
<re.Match object; span=(0, 7), match='dresses'>
<re.Match object; span=(0, 6), match='dresse'>

Why does the 3rd method only match dresse? I thought anything inside [] are alternatives of each other (select 1 option from (es) vs \b) so it has the same effect as the 1st two regex?

  1. What differences are there between the first two regex? (eg. extensibility, robust against false positives).

  2. How to achieve the same effect using square brackets in 3rd regex and how does that compare to first two regex?

Same thing as this post. The regex engine is parsing each character individually; it sees the character (, the character e, and so on.

I don’t think it can be done. That’s not the spirit behind the square brackets. The square brackets are, I suspect, syntatic sugar to avoid using lots of | in the case on single characters.

None, I don’t think. The (es)?\b in the second pattern bit matches es when not followed by a word character, or it matches “nothing” when not followed by a word character. This description is the same for equivalent portion in the first pattern.