Regex *️⃣
Hello makers,
I hope you're enjoying this Serial Maker newsletter! Join me and other Serial Makers on Discord. Check out the past editions if you missed them. And if you know someone who might benefit from this newsletter, please forward this email to a friend 😀
A regular expression (or regex) is a sequence of characters that define a search pattern. They're used in virtually every programming language to validate, find, replace, or split strings of text. Search engines and text editors use them extensively.
Regular expressions save the day! 😝
For a long time, I never bothered to really learn regex. Most of what you can do with a regex pattern you can accomplish with some programming logic. But there comes a time when nothing else will do, and knowing the basics will add another tool to your coding toolbox.
Let's talk about regular expressions.
TL;DR
Refer to the cheat sheet
Test your regex in RegExr
Do not use regex to parse HTML or to validate an email
Where to start?
In the past, I avoided spending the time to fully understand regex because it's wildly cryptic for newcomers. But there are some really great resources for learning all about regex. For a crash course, check out RegexOne.
Another great way to learn is to try it out in real-time. I love using RegExr as a regex playground. You can even save your regular expressions for future use!
Where can you use regex?
Virtually anywhere. Here are some examples of use cases for regular expressions:
Trim white space. Remove any spaces or line breaks from the beginning or end of a string.
Parse a hexadecimal value. Grab the hex values and convert them to RGB or another color space.
Validate a username. Make sure usernames only contain letters, and are a certain length.
Enforce password complexity. Ensure passwords include uppercase and lowercase letters, a number, and a special character.
Where should you not use regex?
Two common use cases that are considered a bad use of regular expressions are emails and HTML.
Emails can actually be quite complex, and a regex will likely never cover every single possible valid email. But more importantly, emails should be verified through a token response system. Anyone can claim to have an email, but a truly verified email would require that person to verify they own the account, not just that it's formatted correctly.
Should regular expressions be used to parse complex HTML? One of my favorite Stack Overflow answers addresses this question as only Stack Overflow can do. The short answer is no. There are parsing libraries specifically built for just this purpose. Use them instead.
A real-world example
Want to see all this in action? I was recently tasked with enforcing password complexity in an app to meet a company's security standards.
I wrote this regular expression yesterday:
\A(?=[^0-9]*[0-9])(?=[^A-Z]*[A-Z])(?=[^a-z]*[a-z])(?=[^!@#$%^&*()_+\-={};':",.\/<>?]*[!@#$%^&*()_+\-={};':",.\/<>?])(?:(.)\1?(?!\1))+\z
Holy smokes, you say! What is this nonsense?
Let's break it down into parts.
\A
This indicates the start of a string
(?=[^0-9]*[0-9])
The parentheses group this part together. Let's break this section down further.
?=
This indicates a positive lookahead (it looks for a match after the expression without including it in the results).
[^0-9]
The square brackets indicate a set of characters. 0-9 includes all numerical digits. The caret flags this set as a negated set (it will match anything that is not a number).
*
This is a quantifier that indicates we need to match any number of the preceding set.
[0-9]
Again, the square brackets indicate a set of characters, and 0-9 includes all numerical digits.
So that entire group (?=[^0-9]*[0-9]) will match any numerical digit not preceded by another numerical digit. Let's move onto the next group.
(?=[^A-Z]*[A-Z])
This does the same thing as the above group, but with capital letters. A-Z represents any capitalized letter. This group will match any uppercase letter not preceded by another uppercase letter.
(?=[^a-z]*[a-z])
Similarly, this will match any lowercase letter not preceded by another lowercase letter. Are you getting the hang of this yet?
(?=[^!@#$%^&*()_+\-={};':",.\/<>?]*[!@#$%^&*()_+\-={};':",.\/<>?])
This group looks more complicated, but it's the same principle. Instead of indicating a range of characters, we're specifying each specific character we want to include in the set. The backslash before the dash \- and the forward-slash \/ escape those characters. Without escaping them, the dash would indicate a range, and the forward-slash would be used as an indicator for the start/end of a regex, depending on the programming language. This group will match any of the special characters indicated, not preceded by another special character.
(?:(.)\1?(?!\1))
Another group. Let's break this one down and see what it's doing.
?:
This indicates a non-capturing group. The expression will not include any characters in this as part of the result.
(.)
This captures any character (except line breaks, which we don't have in a password). It's grouped with parentheses for what we do next
\1?
The \1 is a numeric reference that matches the results of capture group number 1 (the any character group we specified above). The question mark means we need zero or one match. Okay, moving onto the next sub-group (?!\1).
?!
This indicates a negative lookahead. If we find a match with the next expression, we discard it.
\1
Again, we're referencing the any character group (.) above. By placing an any character match, followed by the same match, and then followed by no match, we've ensured that we never match more than two of the same character in a row.
+
This quantifier will repeat the preceding expression an infinite number of times.
\z
This indicates the end of a string.
Whew! So what does all of this put together mean? This will ensure that a password has at least one numerical digit, at least one uppercase letter, at least one lowercase letter, at least one of our acceptable special characters, and never repeats the same character more than twice in a row.
Don't believe me? Go ahead and try it out: https://rubular.com/r/Ohqdycv09sSj8L
It's easier with a cheat sheet
Once you understand the underlying principles of regular expressions, you'll be able to read and write your own. But all those quantifiers and matches are hard to memorize, so it's useful to keep a cheat sheet handy with all of the syntax explained. Cheatography has a nice one.
Are you using regex in your work? I'd like to hear all about it.
Keep making, and thanks for reading! 🙌
Hit reply to tell me what you're making. I'm looking for anyone interested in talking about their own side-projects and maker journey, so speak up if you'd like to appear in Serial Maker. I'd also love to know what you thought of this issue, and what you want to hear about in the future. And don't forget to continue the conversation on Discord!
Until next week,
Craig


