For #1, \1
matches what the group actually matched, not what it could have matched, which is I suspect the root of your confusion. The .
resolves to a specific character (e.g. a
), then the \1*
resolves to zero or more a
s, not zero or more "any characters". Since no character is repeated, you only match a single character at a time.
In #3, you match only empty strings, because there are no longer strings that repeat in the input, so \1
only applies when (.*)
captured nothing (the empty string), which it does once at the beginning, end, and in-between each character in the input.
Both of the above are pretty straightforward if you know regex syntax. But #2 is the weird one, in that it matches the whole string (.*
captures the whole thing), then, in an arguably incorrect follow-on, matches the "following" empty string, and replaces each, leading to two hyphens.
Really, the short answer to your entire question is "*
is an unsafe/non-intuitive quantifier to start with, and applying it to .
makes it worse". Try to use +
where at all possible, as it avoids these "match nothing" weirdo cases.