Software

What Is Regex? Regular Expressions Explained With Examples

Talha Aslan 19 min read 5 views

What is regex, and why does every developer eventually need it? In this guide, we at Talha Aslan and team walk you through regular expressions from the definition to syntax, validation patterns, language differences and performance risk. There are no code blocks here. You only get short inline examples you can try right away.

What is regex?

Regex (short for regular expression) is a compact language for describing a pattern of characters to find in text. For example, the pattern \d+ means "one or more digits." Developers rely on regex to search, validate, extract and replace text, and almost every programming language and code editor supports it.

In short, regex lets you say "find everything that follows this rule" instead of "find this exact word." As a result, one line of pattern can replace dozens of lines of loops and conditions. However, that power comes with a cost in readability and maintenance. Later in this guide, we also cover when regex is the right tool and when you should pick something else.

The term comes from formal language theory in computer science. Modern engines add practical extras on top of that theory, such as backreferences and lookarounds. So what we call "regex" today is a slightly larger family of tools than the strict theoretical model.

What is regex in plain terms, with an everyday analogy?

Imagine asking a librarian for "books with the word history on the cover." That is a plain text search. Now imagine asking for "shelf labels that start with a four digit year, then a dash, then a two digit month." That second request is regex thinking. The first names a word, while the second describes a shape.

A cookie cutter is another useful picture. You press the cutter into the dough, and every piece that fits the shape comes out. A regex pattern works the same way on text. The engine slides it from left to right and hands you the pieces that fit.

The analogy also hides a warning. If you draw the cutter badly, you get the wrong pieces. Therefore, you should think first about what you want to match and then about what you must never match. In our experience, most regex bugs come from skipping that second question.

How does a regex engine scan text?

First, the engine compiles your pattern into an internal structure. Then it tries to fit the pattern starting at the first character of the input. If the match fails, it moves to the next starting position. That is why a pattern can match anywhere inside a string.

Most popular engines rely on a method called backtracking. The engine picks a path, and when the path hits a dead end, it steps back and tries another option. For example, with a.*b the engine first swallows as many characters as it can. After that, it gives characters back one by one until it finds a b.

Some engines take a different approach. They guarantee a running time that grows in a straight line with the input length. That said, these engines usually skip features such as backreferences. This difference matters a lot in the performance section below.

In practice, you do not need to memorize engine internals. Still, it helps to remember one fact: a backtracking engine may try every possible path. Keeping that in mind lets you spot slow patterns early.

What do character classes do?

A character class is a set of characters that may appear at a single position. You write it in square brackets: [abc] accepts a, b or c. You can also give a range. For instance, [0-9] covers any digit and [a-z] covers lowercase English letters.

Common classes also have shorthand forms:

  • \d: one digit.
  • \w: a "word character" such as a letter, digit or underscore.
  • \s: whitespace, such as a space, tab or line break.
  • .: by default, any character except a line break.
  • [^0-9]: a leading caret flips the set, so this means "anything but a digit."

Be careful with text in other languages. For example, [a-z] does not include letters such as é, ü or ç. Also, in some languages \w covers Unicode letters, and in others it does not. Because of this, check the Unicode behavior in your language's documentation before you process international data.

How do quantifiers work?

A quantifier tells the engine how many times the previous item may repeat. There are four core quantifiers. A star * means zero or more. Next, a plus + means one or more. The question mark ? means zero or one, and {n,m} means at least n and at most m.

For example, \d{3} requires exactly three digits. Similarly, \d{2,4} accepts two to four digits. The pattern colou?r matches both "color" and "colour" because the question mark only makes the letter u optional.

People often miss one detail here. A quantifier applies only to the item right before it. If you want to repeat a whole word, you need to wrap it in parentheses. In other words, ha+ matches "haaaa," while (ha)+ matches "hahaha."

Also, nesting quantifiers inside each other is the root of the risks you will see in the performance section. A simple looking repeat can keep the engine busy for seconds on the wrong input.

Why do groups and captures matter?

Parentheses do two jobs. First, they turn several items into one unit, so a quantifier can apply to that unit. Second, they "capture" the matched part. You can then reach that part separately in your code.

For example, (\d{4})-(\d{2})-(\d{2}) finds a date and stores the year, month and day in three groups. In a replace operation, you refer to these groups by number. Then turning "2024-05-17" into day, month, year order becomes a one line job.

If you do not need the capture, use a non capturing group: (?:...). This form states your intent clearly and keeps group numbers tidy. Many languages also support named groups. A named group removes the "what was group three again?" problem in long patterns.

Inside a group, the pipe | offers alternatives. For instance, (jpg|png|webp) accepts any of three file extensions. Put simply, groups shape both the structure of a pattern and the data you get out of it.

What do anchors and boundaries mark?

An anchor stands for a position, not a character. The caret ^ marks the start of the text or line, and $ marks the end. The token \b is a word boundary. It marks the invisible point between a word character and a non word character.

Anchors are critical for validation. For example, \d{5} also finds a match inside "abc12345xyz," because a partial fit is enough. In contrast, ^\d{5}$ accepts only text that is exactly five digits from start to end.

Word boundaries also make searches cleaner. The pattern \bcat\b finds the word "cat" but skips "category" and "concat." However, \b depends on the definition of a word character. As a result, it can behave differently with accented letters across languages.

In multiline text, ^ and $ point to the start and end of the whole input by default. If you want each line on its own, you need to switch on the multiline flag. We cover flags briefly in a later section.

What is the difference between greedy and lazy matching?

Quantifiers are greedy by default. In other words, they take as many characters as possible and give some back only when needed. A lazy version settles for as few characters as possible. You make a quantifier lazy by adding a question mark after it: *? or +?.

For example, take a line with two quoted words: "apple" and "pear." The greedy pattern ".*" grabs everything from the first quote to the last quote as one piece. The lazy pattern ".*?" captures each quoted word separately. In data extraction, that is the gap between a correct result and a broken one.

On the other hand, a lazy quantifier is not always the best fix. In many cases, a negated character class is clearer and faster. For instance, "[^"]*" says "anything that is not a quote" and does the same job without extra backtracking.

So before our team writes a lazy quantifier, we ask a quick question. Do we know which character must not appear here? If the answer is yes, a negated class usually gives a sturdier pattern.

How do flags change a match?

A flag is a setting that applies to the whole pattern. The syntax differs between languages, but the ideas stay the same. These are the flags you will meet most often:

  1. Case insensitive: "Regex" and "regex" count as the same.
  2. Multiline: ^ and $ mark the start and end of each line.
  3. Dot all: the dot . also matches line breaks.
  4. Global: the engine finds every match instead of stopping at the first.
  5. Unicode: letter classes follow Unicode rules.

Case insensitive matching has traps in some languages. For example, Turkish has dotted and dotless forms of the letter i, so its case rules differ from English. Therefore, normalizing text to one consistent case before matching is often safer. You can quickly convert text with our case converter tool.

What are lookarounds and backreferences?

Once you know the answer to "what is regex" at a basic level, you will meet advanced features. First comes the lookahead. A lookahead checks whether a pattern follows a position but does not include those characters in the match. For example, \d+(?=USD) finds only numbers followed by "USD."

A negative lookahead does the opposite. It selects positions where a pattern does not follow. You will often see password rules such as "must contain a digit" written this way. Still, separate simple checks are usually easier to read than one clever pattern.

A backreference lets you match the same text that an earlier group captured. For instance, (\w+) \1 finds repeated words such as "the the." Then you can catch accidental duplicates during proofreading in seconds.

That said, not every engine offers these features, and they can strain performance. In practice, a full answer to "what is regex" at an advanced level includes knowing which languages support them.

How should you use regex for email validation?

Email validation is the most common follow up question after "what is regex." Here is the short answer. Use regex to check that an address looks roughly right. Then confirm that it actually works by sending a verification email.

A pattern that fully follows the email standards is extremely long and hard to read. Moreover, it adds little value, since a well formed address may still be unused. A reasonable approach is to stay simple. Check for a part without spaces, an @ sign, then a domain that contains at least one dot.

Example scenario: on a contact form, a visitor types their address with an accidental space. A simple pattern catches this instantly and shows a friendly hint. In contrast, an overly strict pattern may reject new domain endings or addresses with a plus sign. That way, you lose real customers.

Also, browsers run their own checks on email input fields. On the server side, always repeat validation. Client side checks only improve user experience and do not count as a security measure. For sample addresses, stick to reserved domains such as example.com.

What should you watch for with phone numbers and dates?

With phone numbers, the real issue is format variety. Users may add spaces, dashes, parentheses or a country code. So normalize the text first. Strip non digit characters with a pattern such as [^\d+], then check the length of what remains.

This way, you replace one complex pattern with two simple steps. The first step cleans the data, and the second applies the rule. Because valid lengths vary by country, packing the full rule into a single regex is usually a mistake.

With dates, regex checks only the format. For example, ^\d{4}-\d{2}-\d{2}$ happily accepts "2024-02-31," even though February has no 31st day. In short, calendar logic is not a regex job.

The right flow is simple. First, use regex to filter the format quickly. Next, let your language's date library try to parse the text into a real date. If parsing fails, the date is invalid. This two layer approach stays readable and reliable.

How do regex flavors differ between programming languages?

Regex is not one single standard. Instead, it is a family of flavors that share a common core. Character classes, quantifiers and groups look almost the same everywhere. Differences start with the advanced features.

For example, in JavaScript you write a pattern between slashes and add flags at the end. The MDN regular expressions guide covers the details. Python handles patterns through the re module and recommends raw strings (r"...") to avoid backslash confusion. The official Python re documentation explains this in depth.

The main points where flavors differ include:

  • Named group syntax and how you refer to groups in replacements.
  • Lookbehind support and its limits.
  • Default Unicode behavior of character classes.
  • Flag names and which flags exist.
  • No backreference support at all in some engines.

Consequently, always test a pattern when you move it from one language to another. If you work with Python, our guide to the most popular Python libraries gives a wider view of the text processing ecosystem.

What is ReDoS, and how do you protect regex performance?

ReDoS (Regular expression Denial of Service) happens when a badly built pattern runs for an extremely long time on certain inputs and stalls the application. The OWASP ReDoS page describes this as catastrophic backtracking in engines that try many paths for nested repeats.

The risky shape is usually a repeat inside a repeat, such as (a+)+. When the match fails, the engine tries every possible way to split the characters among the groups. As the input grows, the number of attempts explodes.

On the defense side, you can take these steps:

  1. Avoid nested quantifiers and use a single level of repetition where possible.
  2. Write alternatives that do not overlap, so the same text cannot match two ways.
  3. Limit the length of user input before the regex runs.
  4. Use a timeout option if your language or library offers one.
  5. Consider an engine with a linear time guarantee for critical paths.
  6. Never run text from users directly as a pattern.

In addition, watching server logs for sudden slowdowns gives you an early warning. Our log file analyzer can help you find requests that take too long.

Regex vs plain text search vs a parser

Picking the right tool saves more time than writing a clever pattern. The table below compares the three approaches side by side:

CriterionPlain text searchRegexParser
What it findsA fixed word or phraseAny text that fits a ruleThe full structure of a format
Learning curveAlmost noneMediumHigh, but libraries do most of the work
Nested structureNot supportedLimited and fragileSupported by design
ReadabilityVery highDrops as patterns growClear code and rules
Performance riskVery lowReDoS with bad patternsUsually predictable
Typical useFinding a word in a fileFormat checks, extractionHTML, JSON, YAML, source code

In short, if you are looking for fixed text, regex is overkill. If you process a nested data format, regex falls short. For example, you should read YAML files with a proper parser. We explain that format in our guide on what YAML is and how it compares to JSON.

Common mistakes after you ask "what is regex"

Anyone who has just answered "what is regex" for themselves tends to hit the same few mistakes. Knowing them ahead of time saves hours of debugging.

  • Leaving the dot unescaped: . means "any character," so write \. for a real dot.
  • Forgetting anchors: without ^ and $, validation only checks part of the text.
  • Overmatching with greedy quantifiers: you get surprisingly long matches between quotes or tags.
  • Backslash confusion: string escaping rules and regex rules stack on top of each other.
  • Ignoring accented letters: [a-z] does not cover é or ü.
  • Packing everything into one giant pattern: you end up with a line nobody can maintain.

The shared fix is testing. For every pattern, prepare a few "should match" and a few "should not match" samples. Then, when you change the pattern, you see right away what broke.

Where does regex help in real projects?

Regex saves time on many small but frequent tasks in everyday software work. Below, we summarize use cases our team often sees, framed as example scenarios.

Example scenario one: an old phone number appears across product descriptions in an online store. With one regex in your editor, you find every written form of that number and replace it with the new one.

Example scenario two: you need lines with a specific error code from server logs, plus the URLs on those lines. A grouped pattern selects the line and also returns the URL as a separate column.

Example scenario three: you changed the URL structure of a website and need to redirect old paths to new ones. Server redirect rules often accept regex. To produce clean URL paths, you can also use our slug generator.

Also, bulk renames in code, form field validation and data cleanup are classic regex territory. To track code changes safely, take a look at our Git and GitHub guide.

Should you use regex on API and webhook data?

API responses usually arrive in structured formats such as JSON. In that case, use your language's JSON parser instead of pulling fields out with regex. Otherwise, a change in field order, spacing or escape characters can quietly break your pattern without any error.

On the other hand, validating a single field after parsing is a good regex job. For example, you can check that an order number follows a specific format. We explain the basics of APIs in our article what is an API.

Likewise, with webhook notifications you should first verify the signature and then parse the body. Regex comes in only after that, to check the format of individual fields. You can find the full webhook flow in our guide what is a webhook.

Put simply, the rule is easy to remember. Leave the structure to the parser and the single value to regex. This split reduces bugs and makes life easier for the next developer who reads the code.

How do you write readable, maintainable regex?

A pattern looks clear on the day you write it. Six months later, it can feel like a riddle. That is why you should plan for readability from the start.

First, split the pattern into parts. Many languages let you build a pattern from variables. For example, when you define "year," "month" and "day" pieces with their own names and then join them, the pattern explains itself.

Second, use verbose mode where your language supports it. Verbose mode ignores whitespace and lets you write comments inside the pattern. The Python documentation describes this mode in detail.

Third, rely on named groups. Writing "day" in code instead of "group 3" clearly lowers the risk of mistakes during changes.

Finally, keep a small list of tests next to every pattern. When you change the pattern, the tests answer right away. As a result, regex stops being a scary black box and gets the same care as any other code.

A practical checklist after you learn what regex is

Before you ship a pattern to production, we suggest you run through this list:

  1. Would plain text search or an existing parser do the job?
  2. If I am validating, do I have anchors at the start and the end?
  3. Did I escape special characters such as the dot, plus and parentheses?
  4. Does the data contain accented or other Unicode characters?
  5. Does any part contain a nested repeat or overlapping alternatives?
  6. Did I limit the input length?
  7. Did I test with at least five matching and five non matching samples?
  8. If I am moving the pattern to another language, did I check its documentation?

This list looks short, but it catches most regex problems that reach production. Items five and six matter most for security. To measure text length quickly, our word counter also comes in handy.

When is regex the wrong tool?

Regex is powerful, but it does not fit every problem. Nested formats such as HTML, XML or JSON are the best known example. In these formats, tags or brackets can nest as deeply as they like. Regular expressions cannot reliably track that depth.

Also, if business rules change often, readable code beats a long regex. For example, a rule such as "a tax ID is required for business customers" belongs in a conditional statement, not in a pattern.

Natural language processing is a separate field as well. Trying to detect whether a sentence sounds positive or negative with regex quickly turns into a fragile mess. For that kind of work, language models and dedicated libraries fit better.

In short, regex gives the best results for well defined, flat text patterns. If your pattern starts to look like a paragraph, it is time to stop and consider another approach.

How does our team handle regex in projects?

At Talha Aslan and team, we use regex in small, tested and documented pieces in web projects. We run format checks in the validation layer and keep business logic in separate code.

For every pattern that touches user input, we review the length limit and the ReDoS risk. In addition, before we add a pattern to a project, we prepare a small test set of matching and non matching samples. That way, later changes do not quietly introduce bugs.

When you hesitate about regex in a project, ask one question. Could another developer read and understand this pattern in six months? If not, split it, name its parts or replace it with plain code. This habit noticeably lowers maintenance cost across a team.

If you are planning a custom application that needs text processing, from form cleanup to redirect rules and log analysis, we can plan it together through our custom software development service.

One last tip: the fastest way to learn regex is to solve a real small problem. Start with a simple task, such as finding the dates in a file or checking email formats in a list. Then run your tests at every step.

Frequently Asked Questions

What is regex, and which languages support it?
Regex is a short language for describing a pattern of characters to find in text. Nearly all popular programming languages support it, including JavaScript, Python, Java, PHP, C# and Go. Many code editors and command line tools also let you search and replace with regex. However, flavors differ in advanced features, so always check your language's documentation.
Is regex hard to learn?
The basics are not hard. With character classes, quantifiers, groups and anchors, you can solve most everyday tasks. The difficulty shows up when you read and maintain long patterns. That is why we suggest starting with small patterns and testing each one with matching and non matching samples. With regular practice, you will feel comfortable within a few weeks.
Can regex fully validate an email address?
No, regex only checks the rough format. A pattern that fully follows the standards becomes very long and hard to read. It also cannot prove that anyone actually uses the address. A sensible approach is a simple format check followed by a verification email. Always repeat the check on the server side as well.
How can I reduce ReDoS risk?
Start by avoiding nested repeats and by writing alternatives that do not overlap. Limit the length of user input before the regex runs. Use a timeout if your language offers one, and consider an engine with a linear time guarantee for critical paths. Above all, never run text that comes from users directly as a pattern.
When should I use greedy or lazy matching?
The default greedy quantifier looks for the longest possible match, and that works in most cases. A lazy quantifier helps when you want short pieces between quotes or brackets one by one. That said, if you know which character must not appear, a negated character class usually gives a clearer and faster solution than either option.
Can I parse HTML or JSON with regex?
We do not recommend it. HTML and JSON contain nested structures, and regex cannot track that depth reliably. A small format change can quietly break your pattern. Instead, use the ready made parser in your language. Keep regex for narrow, well defined jobs, such as checking the format of a single field after parsing.
  • regex
  • regular expressions
  • software development
  • data validation
  • redos
  • programming basics
Share:
Talha Aslan

Google Partner digital marketing expert. Hands-on with SEO, Google Ads, web design and e-commerce projects since 2012; every post here comes from that experience.

Next project

Get a quote for your project.

Your brief goes straight to Talha Aslan and team: strategy led by Talha, delivery by an experienced team. We reply the same day and send the scope, timeline and price as a written quote within 1 business day.