Regular expression in Java and
springBoot
Java Regular Expressions (Regex)
Introduction
Regular expressions (regex) are a powerful tool for processing text. They
allow you to search, manipulate, and edit strings based on specific
patterns. In Java, the [Link] package provides classes for matching
character sequences against patterns specified by regular expressions.
This beginner's guide will introduce you to Java regular expressions,
teaching you how to use them through simple, easy-to-understand
explanations and plenty of code examples.
Understanding Regex in Java
Java provides the [Link] package, which contains classes like
Pattern and Matcher to perform regex operations. The Pattern class is used
to define a pattern (the regex itself), while the Matcher class is used to
search for the pattern within a string.
Before diving into the examples, let’s understand some basic regex
components:
Literals: These are the simplest form of pattern matching. For instance,
the regex dog matches the string "dog".
Character Classes: Denoted by square brackets [], they match any one
of the characters contained within them. For example, [abc] matches
"a", "b", or "c".
Predefined Character Classes: Java regex offers predefined character
classes like \d for digits, \s for whitespace, and \w for word characters
(letters, digits, and underscores).
Quantifiers: Specify the number of occurrences to match. For example,
+ means one or more times, * means zero or more times, and ? means
zero or one time.
📘 Basic Regex Components in Java
✅ 1. Literals
A literal matches the exact text:
Matches: "dog"
✅ 2. Character Classes
Use square brackets to match one character from a set:
Matches: "a", "b", or "c"
You can also use ranges:
Matches any lowercase letter from a to z.
✅ 3. Predefined Character Classes
Regex Meaning Matches
\d Digit 0-9
\w Word a-z, A-Z, 0-9, _
\s Whitespace space, tab, newline
Example:
✅ 4. Quantifiers
Symbol Meaning Example Matches
* 0 or more a* "", "a", "aa", etc.
+ 1 or more a+ "a", "aa", not ""
? 0 or 1 a? "", "a"
{n} Exactly n a{3} "aaa"
{n,} n or more a{2,} "aa", "aaa", ...
{n,m} Between n and m a{2,4} "aa", "aaa", "aaaa"
These commonly used regex patterns form the foundation of real-world string matching in
Java and Spring Boot applications — especially for validations, text parsing, or data
extraction.
🔤 Commonly Used Regex Patterns in Java (with Examples)
✅ 1. Digits – \\d
Matches any single digit (0-9).
To match exactly 5 digits (e.g., ZIP code): \\d{5}
🧩 Spring Boot Validation Example:
✅ 2. Word Characters – \\w
Matches any letter, digit, or underscore ([a-zA-Z0-9_])
🧩 Use case: Validating usernames
✅ 3. Whitespace – \\s
Matches spaces, tabs, newlines, etc.
🧩 Useful for removing extra spaces:
✅ 4. Literal Characters – "cat"
Matches exactly the string cat (no regex wildcards)
🧩 Spring Boot REST Example: Search a keyword in a post body.
✅ 5. Wildcard Character – .
Matches any single character except newline.
Output:
🛠 Spring Boot Real-world Use Cases
Pattern Use Case
\\d{10} Validate mobile numbers
\\w+@\\w+\\.com Validate email addresses
`^\s+ \s+$`
.*error.* Log scanning or error tracking
.*\\.pdf$ Match file extensions in upload/download
logic
🧠 Tip: Always Escape Backslashes in Java
Java strings treat \ as a special character, so in regex you must write \\d, \\s, \\w, etc.
so in spring can i use single \
❌ No — you cannot use a single backslash (\) directly in regex patterns in Java, including in
Spring Boot.
📌 Why?
Java treats \ as an escape character in strings. So when you write a regex pattern like \d or \s,
Java expects \\ (double backslash) to represent a literal backslash in the compiled regex.
✅ Example: Correct usage in Java (and Spring Boot)
✅ Java String version:
✅ Spring Boot Validation (DTO):
❌ Incorrect (will throw exception or not match properly):
🧠 Think of it like this:
You want to write... You type in Java
\d (digit) "\\d"
\s+ (spaces) "\\s+"
\w{5,} (word chars) "\\w{5,}"
✅ Tip for easier writing:
Use Raw Strings if you're using Kotlin or Java 21+ (preview). But for regular Java 8–17 and
Spring Boot — always double the backslash.
Advanced Pattern Matching
Advanced pattern matching in Java regular expressions introduces more
complex concepts such as lookahead and lookbehind assertions, non-
capturing groups, and backreferences. These features enable intricate
matching scenarios that go beyond basic pattern matching capabilities.
Lookahead and Lookbehind Assertions
Lookahead and lookbehind assertions allow you to include or exclude
certain patterns based on what comes before (lookbehind) or after
(lookahead) your match without including those patterns in the match
itself.
Positive Lookahead (?=pattern): Matches a group after the main
expression without including it in the result.
Negative Lookahead (?!pattern): Specifies a group that should not
follow the main expression.
Positive Lookbehind (?<=pattern): Matches a group before the main
expression without including it in the result.
Negative Lookbehind (?<!pattern): Specifies a group that should not
precede the main expression.
Great! Let's now take your explanation of advanced regex pattern matching (lookahead,
lookbehind, etc.) and apply it to a real Spring Boot use case — like custom validation, user
input filtering, or secure pattern enforcement (e.g., password rules).
✅ Spring Boot + Advanced Regex Matching
We’ll walk through:
1. Basic setup
2. Examples using lookahead/lookbehind in validation
3. Custom annotation (if needed)
📦 1. Example: Regex with Lookahead in Spring Boot DTO
Validation
🔐 Goal: Enforce a secure password
At least 1 uppercase
At least 1 lowercase
At least 1 digit
At least 1 special character
Minimum 8 characters
✅ Use positive lookaheads to enforce inclusion of each character type.
📘 Explanation:
(?=.*[a-z]) → at least one lowercase
(?=.*[A-Z]) → at least one uppercase
(?=.*\\d) → at least one digit
(?=.*[@$!%*?&]) → at least one special char
📦 2. Example: Email Field That Must Not Start With a Number
(Lookbehind)
⚠️ Java regex doesn’t support variable-length lookbehind, but you can still do:
Explanation:
(?!\\d) = negative lookahead: disallow starting with a digit
Then follows normal email validation
📦 3. Advanced: Repeated Word Detection (Backreference) in
Text Field
You can detect duplicate consecutive words using backreferences:
💡 Matches: "hello hello" but not "hello world"
🛠 Optional: Custom Regex Validator with Lookahead
If you want more control, create a custom validator:
🔹 Annotation
🔹 Validator
🔹 Usage in DTO
✅ Summary of Advanced Regex in Spring Boot
Regex Type Java Support Spring Boot Use Case
Lookahead (?=...) ✅ Enforce required
characters in password
Lookbehind (?<=...) ✅ (fixed-width only) Filter based on prefix
Negative Lookahead (?!...) ✅ Disallow starting pattern
(e.g., number in email)
Backreference (\\1) ✅ Catch duplicate words or
patterns
Non-capturing Group (?:...) ✅ Group without counting
Spring - MVC Regular Expression Validation
Regular Expression Validation in Spring MVC can be achieved by using Hibernate
Validator which is the implementation of Bean Validation API. Hibernate
Validator provides @Pattern annotation which is used for regular expression
validation.
Syntax:
@Pattern(regex="", flag="", message="")
private String someDataMember;
Note that the flag and message attributes are optional. Let's build a simple web
application for a better understanding of how to use Regex validation in Spring
MVC. In this application, we will build a guest login page.
Example
Project structure:
Project structure for guest login application
Regex Usage:
The @Pattern annotation makes sure that the value passed to the data member
follows the provided regular expressions. The attribute regexp takes the regular
expression to be matched.
@Pattern(regexp = "^[a-zA-Z0-9]{6,12}$",
message = "username must be of 6 to 12 length with no special characters")
private String username;
In the above code snippet, the regular expression says that a username can
contain any lowercase characters, any uppercase characters, or any digit only.
Also, the username can only be of 6 to 12 lengths (inclusive).
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#$%^&*])[a-zA-Z0-9!@#$%^&*]
{4,12}$",
message = "password must be min 4 and max 12 length containing atleast 1
uppercase, 1 lowercase, 1 special character and 1 digit ")
private String password;
In the above code snippet, the regular expression says that the password must
contain at least 1 lowercase letter, 1 uppercase letter, 1 special character, and 1
digit and it must be of size 4 to 12 inclusive.
User class (Data model):
import [Link];
import [Link];
import [Link];
import [Link].*;
@Data
@AllArgsConstructor
@NoArgsConstructor
class User {
@Pattern(regexp = "^[a-zA-Z0-9]{6,12}$",
message = "username must be of 6 to 12 length with no special characters")
private String username;
@Pattern(regexp = "^((?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$&*])(?=.*[0-9])){4,12}$",
message = "password must contain atleast 1 uppercase, 1 lowercase, 1 special character and 1
digit ")
private String password;
The User class acts as a data model for our application. Here we have used
Lombok to reduce boilerplate code. The User class consists of only 2 fields
required for our guest login page.
APIs: Our application consists of the following APIs.
@GetMapping("/")
public String getForm(User user) {
return "login";
The above code snippet demonstrates the GET API which is used here to render
the [Link] page residing in our resources/templates files. The endpoint for
the GET API is "/".
@PostMapping("/")
public String login(@Valid User user, Errors errors, Model model) {
if ([Link]()) {
return "login";
} else {
[Link]("message", "Guest login successful ...");
return "login";
The above code snippet demonstrates the POST API which is used to take login
form input and passes the errors (if any) of the regex validation to the login page
which then renders it.
Complete Controller Class:
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
@Controller
public class LoginController {
@GetMapping("/")
public String getForm(User user) {
return "login";
@PostMapping("/")
public String login(@Valid User user, Errors errors, Model model) {
if ([Link]()) {
return "login";
} else {
[Link]("message", "Guest login successful ...");
return "login";
Note :
The @Controller annotation indicates that a particular class serves the role
of a controller.
@GetMapping is used to handle GET type of request method.
@PostMapping is used to handle POST type of request method.
Login page (Html + Thymleaf):
<!DOCTYPE html>
<html lang="en" xmlns:th="[Link]
<head>
<title>Guest Login</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet"
href="[Link]
<script src="[Link]
<script src="[Link]
<script src="[Link]
</head>
<body>
<h1 th:text="${message}" style="text-align: center; padding-top: 40px"></h1>
<div class="container" style="padding-top: 50px ">
<h2>Guest login</h2>
<form action="/" th:action="@{/}" th:object="${person}" method="post" style="padding-top:
30px">
<div class="form-group">
<label for="username">Username:</label>
<input type="text" class="form-control" id="username" placeholder="Enter username"
name="username" th:field="*{username}"> <br />
<p th:if="${#[Link]('username')}" th:errors="*{username}" class="alert alert-
danger"></p>
</div>
<div class="form-group">
<label for="password">Password:</label>
<input type="text" class="form-control" id="password" placeholder="Enter password"
name="password" th:field="*{password}"> <br />
<p th:if="${#[Link]('password')}" th:errors="*{password}" class="alert alert-
danger"></p>
</div>
<div class="form-group form-check">
<label class="form-check-label"> <input class="form-check-input" type="checkbox"
name="remember">
Remember me
</label>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</body>
</html>
The above code represents our login page. Here we have used thymleaf instead
of JSP which is a templating engine that is certainly a better way of creating
templates.
Dependency:
Add the below dependencies in the [Link] file.
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>hibernate-validator</artifactId>
<version>[Link]</version>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>[Link]</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
Output:
Let's try to validate it with some invalid input data. Example:
Username: anu0-0
Password: QWqw123
Since the username doesn't allow special characters and the password requires
a special character, error messages will be passed to the login page and then
rendered showing that the input data doesn't match the given regex format.
Invalid input data
Let's try to validate it with some valid input data. Example:
Username: anu000
Password: QWqw@123
Regex in Custom Validators (Advanced Use)
You can define a custom annotation with regex logic:
And the validator:
Then use it in your DTO:
SpringBoot: Input Validation with
@Pattern Annotation
The @Pattern annotation in Spring validates a string field against a
regular expression. It ensures the input matches a specific pattern, like
email addresses, content types, or custom formats, and can handle
case insensitivity and custom error messages.
Frequently Asked Questions:
What is the purpose of the @Pattern annotation?
A. It validates a string field using a regular expression to ensure it
matches a specified pattern.
Can @Pattern be used for case-insensitive validation?
Yes, by adding the (?i) flag in the regular expression, it supports case-
insensitive matching.
How do you handle custom error messages with @Pattern?
You can provide a custom error message using the message attribute
@Pattern(regexp = "^(?i)(digital|physical)$", message = "Invalid content type")
Can @Pattern restrict inputs to specific values?
Yes, you can use it to restrict a field to a set of allowed values, such as
“admin” or “user”
@Pattern(regexp = "^(admin|user)$", message = "Role must be 'admin' or 'user'")
Can @Pattern be combined with other annotations?
Yes, it’s often used with annotations like @Size and @NotNull to enforce
both length and pattern constraints.
@Size(min = 3, max = 20)
@Pattern(regexp = "^[A-Za-z0-9_]+$")
What happens if the input doesn’t match the pattern?
A validation exception is thrown, and the custom error message is
displayed to the user.
Can @Pattern be used for validating email or phone numbers?
Yes, it can enforce formats like email and phone numbers using
appropriate regular expressions.
@Pattern(regexp = "^[A-Za-z0-9]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,6}$", message = "Invalid email format")
How do you make the pattern case-sensitive?
Remove the (?i) flag from the regular expression to make the matching
case-sensitive.
@Pattern(regexp = "^admin$", message = "Role must be 'admin'")
Validating product codes
@Pattern(regexp = "^PROD-[0-9]{4}$", message = "Product code must be in the format 'PROD-XXXX'")