This is a tricky problem! Here is a regular expression testing program. Using it, I found all of our solutions do not work. But a combination of the three solutions does with the addition of using the start ^ and end $ metacharacters.
Code:
#!/usr/bin/perl
(print "$ARGV[1] matches $ARGV[0]\n"), exit(0) if $ARGV[1] =~ /$ARGV[0]/;
print "$ARGV[1] does not match $ARGV[0]\n";
Here are some results.
~ % re "(aa)*b{0,2}" aaabb
aaabb matches (aa)*b{0,2}
~ % re "(aa)*|(aa)*ba*|(aa)*ba*ba*" aaabb
aaabb matches (aa)*|(aa)*ba*|(aa)*ba*ba*
After trial and error, I found that excluding the odd beginning a and the 3rd b are the tough parts. Here's what I ended up with. It's pretty ugly, so I'd like to see it simplified.
~ % re "^((aa)*|(aa)*b{1,2}(a[ab]*)?)$" aabb
aabb matches ^((aa)*|(aa)*b{1,2}(a[ab]*)?)$
~ % re "^((aa)*|(aa)*b{1,2}(a[ab]*)?)$" aabbb
aabbb does not match ^((aa)*|(aa)*b{1,2}(a[ab]*)?)$
~ % re "^((aa)*|(aa)*b{1,2}(a[ab]*)?)$" aaab
aaab does not match ^((aa)*|(aa)*b{1,2}(a[ab]*)?)$