Regex's fearsome reputation mostly comes from reading regex built to be comprehensive — 400-character email validators, URL matchers with 17 groups. Production regex is smaller and calmer than that.
Regex looks terrifying because the regex people share is terrifying. The famous RFC 5322-compliant email pattern is thousands of characters long and nobody writing application code should ever use it. But that's not the regex you need day to day. The regex that shows up in real production work is small, readable, and built from about ten symbols. Learn those, learn where not to reach for regex at all, and most of the fear evaporates.
The characters you'll use constantly
Roughly ten metacharacters cover the overwhelming majority of practical patterns:
.— any single character.*— zero or more of the previous.+— one or more.?— zero or one (optional).^and$— start and end of the string. Anchors. The difference between "contains" and "is exactly."[]— a character class:[aeiou]matches any one vowel.()— a group you can capture or repeat.|— alternation, "this or that."\d— a digit. (Its cousins\wand\s— word character and whitespace — round out the set.)
That's the toolkit. Nearly every readable production pattern is a combination of those, and if you can read them, you can read 80% of the regex you'll ever meet.
Email: the right level of precision
The RFC-perfect email regex is a genuine monster, because the real standard is broader and older than the addresses anyone actually types. As Wikipedia puts it:
"email addresses today follow a specific set of rules originally standardized by the Internet Engineering Task Force (IETF) in the 1980s, and updated by RFC 5322 and 6854."
— Wikipedia, "Email address" (CC BY-SA 4.0)
Those rules permit far more than the addresses you'll ever see, which is why a fully-compliant validator balloons to thousands of characters.
For 99% of applications you don't need it. This is correct and readable: ^[^\s@]+@[^\s@]+\.[^\s@]+$ — "some non-space non-@ characters, an @, more of the same, a dot, more of the same." It rejects the obvious garbage and accepts real addresses. Reach for the monster only when you're writing a mail server, and even then, the real validation is sending a confirmation email — not a pattern.
Phone numbers: don't be clever
Regex cannot validate phone numbers internationally, and trying is a well-known way to waste an afternoon. Number formats, lengths, and country rules are too varied. The pragmatic approach: strip everything that isn't a digit, check the length falls in a sane range, and hand real validation to a proper library like libphonenumber. A "loose validation" regex here should be deliberately forgiving — its only job is to catch someone typing their name into the phone box.
URL matching: two different jobs
People conflate "extract URLs from a blob of text" with "validate that a string is a well-formed URL." They need different regex and one of them is a trap. Extraction is easy and useful — find https?:// followed by non-space characters, good enough. Validation is a false goal: the set of technically-valid URLs is enormous and weird, and your regex will either reject legitimate ones or accept nonsense. If you need to know a URL is real, parse it and try to use it — don't pattern-match it.
Named groups: underused, very readable
Compare (\d{4})-(\d{2})-(\d{2}) with (?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2}). Same match. But six months from now, one of them tells you what it captured and the other makes you count parentheses. Named capture groups cost a few characters and save real confusion when you're pulling fields out of log lines or structured text. Use them any time you capture more than one thing.
The one lookahead worth learning
Lookaheads intimidate people, and mostly you can ignore them — except for one genuinely useful case: "must contain both X and Y, in any order." Password rules are the classic example: at least one letter and at least one digit. Without lookahead you're writing awkward alternations; with it, (?=.*[A-Za-z])(?=.*\d) says "peek ahead and confirm a letter exists somewhere, then peek ahead and confirm a digit exists somewhere" before matching. That single pattern is worth the ten minutes it takes to understand.
Test it live, don't guess
The fastest way to get good at practical regex is to stop writing it in your head. Build and check patterns in a regex tester against real sample input — you'll catch the greedy-* surprise and the unescaped-. bug in seconds instead of in production. Keep a regex cheatsheet open for the symbols you don't use often enough to memorise. And when you're cleaning structured text an LLM produced — stray markdown fences, inconsistent delimiters — the regex for LLM output tool is aimed squarely at that job. Small patterns, tested against real data, beat clever patterns written blind every time.