I avoided regex for three years. Every time I needed one, I'd search Stack Overflow, copy five different solutions until one worked, and move on. It was faster than understanding what I was doing -- until the day a regex I copied matched wrong in production and I had no idea why.
Character classes are everything. \d for digits, \w for word characters, \s for whitespace. Their uppercase versions negate them (\D = non-digit). 90% of regexes you write will use these.
Anchors prevent surprises. ^ and $ are the difference between "contains an email address" and "is an email address." I've seen validation regexes that matched wrong input because someone forgot the closing anchor.
Greedy vs lazy -- this bites everyone. .* is greedy (matches as much as possible). .*? is lazy. When you parse HTML and write <div>.*</div> you get everything from the first div to the last. The lazy version gives you what you wanted.
Fixing catastrophic backtracking is a career skill. The pattern ^(a+)+$ looks innocent but on certain inputs it explodes exponentially. The fix: don't nest quantifiers. Prototype complex patterns in a tester before shipping them.