← back to blog
4 min read
  • #regex
  • #dev-tools
  • #logs
  • #validation

The five regex patterns I actually use

Anchors, classes, quantifiers, groups, and one lookahead trick cover almost everything I do with regex. One real example each, from log grepping and form validation.


Regex has a reputation problem. Every tutorial dumps the full syntax table on you, forty metacharacters deep, and you walk away remembering none of it. So I went through my shell history and my code and counted what I actually type. Almost everything comes down to five patterns.

Here they are, with a real example for each, mostly from two jobs I do all the time: grepping logs and validating form input on small business sites.

Anchors and character classes

1. Anchors: ^ and $

^ means start of the line. $ means end of the line. That is the whole trick, and it kills more false positives than anything else on this list.

When I pull request paths out of the logs for the Susy Nails site, one path per line, and I want to see how the Spanish pages are doing:

grep '^/es/' paths.txt

Without the ^, I would also match junk like /img/es/flag.png. Anchors turn "contains" into "starts with".

They matter even more in validation. [0-9]{5} happily accepts "abc84032xyz" because it found five digits somewhere in the string. ^[0-9]{5}$ accepts a five digit zip code and nothing else. Missing anchors is the most common validation bug I know, and I have shipped it myself.

2. Character classes: [...]

A class matches one character from a set. [0-9] is any digit. [a-z] is any lowercase letter. [^,] is anything except a comma. The shorthands cover the usual suspects: \d for digits, \w for word characters, \s for whitespace.

Real use: a phone field on a salon booking form. People type "435-555-0134", "(435) 555 0134", or "4355550134". Instead of rejecting two out of three paying customers, I strip everything that is not a digit and then check the length:

const digits = value.replace(/[^\d]/g, "");

One negated class, and every format normalizes to the same ten digits.

Quantifiers and groups

3. Quantifiers: + * ? {n,m}

Quantifiers say how many times the thing before them repeats. + is one or more, * is zero or more, ? is optional, {3} is exactly three.

Grabbing dates out of a messy log:

grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}' app.log

Note the [0-9] there. Plain grep does not understand \d. That shorthand needs grep -P or a language engine like JavaScript or Python. Flavor differences like that still bite me, so I test the pattern in the tool I will actually run it in.

One warning: * and + are greedy. They grab as much as they can. ".*" on a line with two quoted strings matches from the first quote all the way to the last one, not the first pair. Add a ? to make it lazy: ".*?". That one character has saved me hours.

4. Groups: ( ) for alternation and capture

Parentheses do two jobs. They let you say "this or that", and they capture what matched so you can reuse it.

Alternation, finding which pages 404 on a site:

grep '" 404 ' access.log | grep -oE '(GET|POST) [^ ]+'

Capture, formatting those phone digits back into something a human can read:

digits.replace(/(\d{3})(\d{3})(\d{4})/, "($1) $2-$3")

Three groups in, "(435) 555-0134" out. Capture groups are also what make log parsing scripts possible: match once, pull the pieces out by number.

Lookahead, the light version

5. Lookahead: (?=...)

Lookahead checks "does this exist ahead of me" without consuming anything. I use exactly one form of it: password rules. "At least one digit, at least one uppercase letter, minimum 8 characters" is ugly to write any other way:

^(?=.*\d)(?=.*[A-Z]).{8,}$

Each (?=...) runs its own check from the start. Stack as many as you need, then let .{8,} do the actual matching.

Full honesty: I had to look up the syntax to write that. Lookahead is the pattern I use least and forget fastest, which is why it lives in a note instead of my head.

Keep them where you can find them

Two limits worth stating plainly. First, regex flavors disagree on details, like grep and \d above, so always test in the real tool. Second, regex is the wrong tool once the input nests. Do not parse HTML with it. Use a real parser and save yourself the pain.

I keep these five patterns in a markdown note with one working example each, because five patterns I can find beat forty I almost remember. Mine lives in the notes tool in Aldo's Toolkit, free on both stores, at /app, next to the flashcards I use for my Security+ study. A text file on your desktop works just as well. The point is to stop re-learning regex from scratch every time a log needs grepping.

$ share

community rating

$ ls ./comments

sign in or create an account to rate and comment.

no comments yet, be first.