String Processing
Regular Expressions Introduction
When validating user input or searching for patterns in text, regular expressions provide a compact language for matching. Regex fundamentals help you write validation, search, extraction, and replacement logic.
Literal Matching
Literal.java
// Literal matching
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class Literal {
public static void main(String[] args) {
// Literal match
String text1 = ;
boolean matches1 = text1.matches("hello");
System.out.println("'hello' matches 'hello': " + matches1);
boolean matches2 = text1.matches("world");
System.out.println("'hello' matches 'world': " + matches2);
// Pattern and Matcher
Pattern pattern = Pattern.compile("hello");
Matcher matcher1 = pattern.matcher("hello");
System.out.println("\nMatcher matches: " + matcher1.matches());
Matcher matcher2 = pattern.matcher("hello world");
System.out.println("Matcher matches 'hello world': " + matcher2.matches());
// Find pattern (doesn't require full match)
Matcher matcher3 = pattern.matcher("hello world");
System.out.println("Find 'hello' in 'hello world': " + matcher3.find());
// Case sensitivity
boolean matches3 = "Hello".matches("hello");
System.out.println("\n'Hello' matches 'hello': " + matches3);
// Case insensitive
Pattern caseInsensitive = Pattern.compile("hello", Pattern.CASE_INSENSITIVE);
Matcher matcher4 = caseInsensitive.matcher("Hello");
System.out.println("Case insensitive match: " + matcher4.matches());
// Multiple occurrences
String text2 = "hello hello hello";
Matcher matcher5 = pattern.matcher(text2);
System.out.println("\nFind all occurrences:");
while (matcher5.find()) {
System.out.println(" Found at index: " + matcher5.start());
}
}
}
// Literal matching
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class Literal {
public static void main(String[] args) {
// Literal match
String text1 = ;
boolean matches1 = text1.matches("hello");
System.out.println("'hello' matches 'hello': " + matches1);
boolean matches2 = text1.matches("world");
System.out.println("'hello' matches 'world': " + matches2);
// Pattern and Matcher
Pattern pattern = Pattern.compile("hello");
Matcher matcher1 = pattern.matcher("hello");
System.out.println("\nMatcher matches: " + matcher1.matches());
Matcher matcher2 = pattern.matcher("hello world");
System.out.println("Matcher matches 'hello world': " + matcher2.matches());
// Find pattern (doesn't require full match)
Matcher matcher3 = pattern.matcher("hello world");
System.out.println("Find 'hello' in 'hello world': " + matcher3.find());
// Case sensitivity
boolean matches3 = "Hello".matches("hello");
System.out.println("\n'Hello' matches 'hello': " + matches3);
// Case insensitive
Pattern caseInsensitive = Pattern.compile("hello", Pattern.CASE_INSENSITIVE);
Matcher matcher4 = caseInsensitive.matcher("Hello");
System.out.println("Case insensitive match: " + matcher4.matches());
// Multiple occurrences
String text2 = "hello hello hello";
Matcher matcher5 = pattern.matcher(text2);
System.out.println("\nFind all occurrences:");
while (matcher5.find()) {
System.out.println(" Found at index: " + matcher5.start());
}
}
}
pattern
A string that defines search criteria. It can include literal characters and special metacharacters.
Character Classes
CharacterClass.java
// Character classes
import java.util.regex.Pattern;
public class CharacterClass {
public static void main(String[] args) {
// Match one of specific characters
System.out.println("a".matches("[abc]")); // true
System.out.println("b".matches("[abc]")); // true
System.out.println("d".matches("[abc]")); // false
// Range
System.out.println("\nRanges:");
System.out.println("5".matches("[0-9]")); // true - digit
System.out.println("m".matches("[a-z]")); // true - lowercase
System.out.println("M".matches("[A-Z]")); // true - uppercase
System.out.println("M".matches("[a-z]")); // false
// Multiple ranges
System.out.println("\nMultiple ranges:");
System.out.println("a".matches("[a-zA-Z]")); // true - any letter
System.out.println("5".matches("[a-zA-Z]")); // false
System.out.println("5".matches("[a-zA-Z0-9]")); // true - alphanumeric
// Negation [^...]
System.out.println("\nNegation:");
System.out.println("a".matches("[^0-9]")); // true - not a digit
System.out.println("5".matches("[^0-9]")); // false - is a digit
// Predefined character classes
System.out.println("\nPredefined classes:");
System.out.println("5".matches("\\d")); // digit
System.out.println("a".matches("\\d")); // false
System.out.println("a".matches("\\w")); // word char
System.out.println(" ".matches("\\s")); // whitespace
System.out.println("a".matches("\\D")); // non-digit
System.out.println("5".matches("\\D")); // false
// Dot . matches any character
System.out.println("\nDot (any char):");
System.out.println("a".matches(".")); // true
System.out.println("5".matches(".")); // true
System.out.println(" ".matches(".")); // true
}
}
character_class
Square brackets such as [abc] match any single character from a set. Ranges such as [a-z] match a span of characters.
Quantifiers
Quantifiers.java
// Quantifiers
public class Quantifiers {
public static void main(String[] args) {
// * (0 or more)
System.out.println("Asterisk * (0 or more):");
System.out.println("".matches("a*")); // true - 0 a's
System.out.println("a".matches("a*")); // true - 1 a
System.out.println("aaa".matches("a*")); // true - 3 a's
System.out.println("b".matches("a*")); // false - not a
// + (1 or more)
System.out.println("\nPlus + (1 or more):");
System.out.println("".matches("a+")); // false - 0 a's
System.out.println("a".matches("a+")); // true - 1 a
System.out.println("aaa".matches("a+")); // true - 3 a's
// ? (0 or 1)
System.out.println("\nQuestion ? (0 or 1):");
System.out.println("".matches("a?")); // true - 0 a's
System.out.println("a".matches("a?")); // true - 1 a
System.out.println("aa".matches("a?")); // false - 2 a's
// {n} (exactly n)
System.out.println("\n{n} (exactly n):");
System.out.println("aa".matches("a{2}")); // true
System.out.println("aaa".matches("a{2}")); // false
System.out.println("a".matches("a{2}")); // false
// {n,} (n or more)
System.out.println("\n{n,} (n or more):");
System.out.println("aa".matches("a{2,}")); // true - 2 a's
System.out.println("aaa".matches("a{2,}")); // true - 3 a's
System.out.println("a".matches("a{2,}")); // false - only 1
// {n,m} (between n and m)
System.out.println("\n{n,m} (between n and m):");
System.out.println("aa".matches("a{2,4}")); // true
System.out.println("aaa".matches("a{2,4}")); // true
System.out.println("aaaa".matches("a{2,4}")); // true
System.out.println("a".matches("a{2,4}")); // false - too few
System.out.println("aaaaa".matches("a{2,4}")); // false - too many
// Practical: digits
System.out.println("\nPractical - validate numbers:");
System.out.println("123".matches("\\d+")); // true - one or more digits
System.out.println("12345".matches("\\d{5}")); // true - exactly 5 digits
System.out.println("123".matches("\\d{2,4}")); // true - 2-4 digits
}
}
quantifier
A symbol that specifies how many times the preceding element should match, such as *, +, ?, or {n}.
Anchors
Anchors.java
// Anchors
public class Anchors {
public static void main(String[] args) {
// ^ (start of string)
System.out.println("Start anchor ^:");
System.out.println("hello".matches("^hello")); // true
System.out.println("hello world".matches("^hello")); // false - matches() requires full match
System.out.println("world hello".matches("^hello")); // false
// For partial matching, use find()
System.out.println("\nUsing find() with ^:");
System.out.println("hello world".matches("hello.*")); // true - starts with hello
System.out.println("world hello".matches("hello.*")); // false
// $ (end of string)
System.out.println("\nEnd anchor $:");
System.out.println("hello".matches(".*hello$")); // true
System.out.println("hello world".matches(".*world$")); // true
System.out.println("world hello".matches(".*world$")); // false
// Both anchors
System.out.println("\nBoth anchors ^...$:");
System.out.println("hello".matches("^hello$")); // true - exact match
System.out.println("hello world".matches("^hello$")); // false
// \b (word boundary)
System.out.println("\nWord boundary \\b:");
String text = "hello world";
System.out.println(text.matches(".*\\bhello\\b.*")); // true - hello as word
System.out.println(text.matches(".*\\bworld\\b.*")); // true - world as word
System.out.println("helloworld".matches(".*\\bhello\\b.*")); // false - no boundary
// Practical examples
System.out.println("\nPractical validation:");
// Must start with letter
System.out.println("abc123".matches("^[a-zA-Z].*")); // true
System.out.println("123abc".matches("^[a-zA-Z].*")); // false
// Must end with digit
System.out.println("abc123".matches(".*\\d$")); // true
System.out.println("abc".matches(".*\\d$")); // false
// Exact length
System.out.println("12345".matches("^\\d{5}$")); // true - exactly 5 digits
System.out.println("1234".matches("^\\d{5}$")); // false
}
}
anchor
An anchor matches a position rather than a character, such as start of string, end of string, or a word boundary.
Groups
Groups.java
// Groups and capturing
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class Groups {
public static void main(String[] args) {
// Basic grouping
String date = ;
Pattern pattern = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher matcher = pattern.matcher(date);
if (matcher.matches()) {
System.out.println("Full match: " + matcher.group(0));
System.out.println("Year: " + matcher.group(1));
System.out.println("Month: " + matcher.group(2));
System.out.println("Day: " + matcher.group(3));
}
// Email parsing
String email = "user@example.com";
Pattern emailPattern = Pattern.compile("([^@]+)@([^@]+)");
Matcher emailMatcher = emailPattern.matcher(email);
if (emailMatcher.matches()) {
System.out.println("\nEmail parts:");
System.out.println("Username: " + emailMatcher.group(1));
System.out.println("Domain: " + emailMatcher.group(2));
}
// Phone number
String phone = "(555) 123-4567";
Pattern phonePattern = Pattern.compile("\\((\\d{3})\\)\\s(\\d{3})-(\\d{4})");
Matcher phoneMatcher = phonePattern.matcher(phone);
if (phoneMatcher.matches()) {
System.out.println("\nPhone parts:");
System.out.println("Area: " + phoneMatcher.group(1));
System.out.println("Exchange: " + phoneMatcher.group(2));
System.out.println("Number: " + phoneMatcher.group(3));
}
// Multiple matches
String text = "Call me at 555-1234 or 555-5678";
Pattern numPattern = Pattern.compile("(\\d{3})-(\\d{4})");
Matcher numMatcher = numPattern.matcher(text);
System.out.println("\nAll phone numbers:");
while (numMatcher.find()) {
System.out.println(" " + numMatcher.group(0) +
" (Area: " + numMatcher.group(1) +
", Num: " + numMatcher.group(2) + ")");
}
// Non-capturing group (?:...)
String url = "https://example.com";
Pattern urlPattern = Pattern.compile("(https?)://(.+)");
Matcher urlMatcher = urlPattern.matcher(url);
if (urlMatcher.matches()) {
System.out.println("\nURL parts:");
System.out.println("Protocol: " + urlMatcher.group(1));
System.out.println("Domain: " + urlMatcher.group(2));
}
}
}
// Groups and capturing
import java.util.regex.Pattern;
import java.util.regex.Matcher;
public class Groups {
public static void main(String[] args) {
// Basic grouping
String date = ;
Pattern pattern = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher matcher = pattern.matcher(date);
if (matcher.matches()) {
System.out.println("Full match: " + matcher.group(0));
System.out.println("Year: " + matcher.group(1));
System.out.println("Month: " + matcher.group(2));
System.out.println("Day: " + matcher.group(3));
}
// Email parsing
String email = "user@example.com";
Pattern emailPattern = Pattern.compile("([^@]+)@([^@]+)");
Matcher emailMatcher = emailPattern.matcher(email);
if (emailMatcher.matches()) {
System.out.println("\nEmail parts:");
System.out.println("Username: " + emailMatcher.group(1));
System.out.println("Domain: " + emailMatcher.group(2));
}
// Phone number
String phone = "(555) 123-4567";
Pattern phonePattern = Pattern.compile("\\((\\d{3})\\)\\s(\\d{3})-(\\d{4})");
Matcher phoneMatcher = phonePattern.matcher(phone);
if (phoneMatcher.matches()) {
System.out.println("\nPhone parts:");
System.out.println("Area: " + phoneMatcher.group(1));
System.out.println("Exchange: " + phoneMatcher.group(2));
System.out.println("Number: " + phoneMatcher.group(3));
}
// Multiple matches
String text = "Call me at 555-1234 or 555-5678";
Pattern numPattern = Pattern.compile("(\\d{3})-(\\d{4})");
Matcher numMatcher = numPattern.matcher(text);
System.out.println("\nAll phone numbers:");
while (numMatcher.find()) {
System.out.println(" " + numMatcher.group(0) +
" (Area: " + numMatcher.group(1) +
", Num: " + numMatcher.group(2) + ")");
}
// Non-capturing group (?:...)
String url = "https://example.com";
Pattern urlPattern = Pattern.compile("(https?)://(.+)");
Matcher urlMatcher = urlPattern.matcher(url);
if (urlMatcher.matches()) {
System.out.println("\nURL parts:");
System.out.println("Protocol: " + urlMatcher.group(1));
System.out.println("Domain: " + urlMatcher.group(2));
}
}
}
capturing_group
Parentheses group parts of a pattern and capture matched text for extraction.
Practical Validation
Regex patterns are often used to validate usernames, emails, phone numbers, passwords, URLs, and dates.
Practical.java
// Practical validation
import java.util.regex.Pattern;
public class Practical {
public static boolean isValidUsername(String username) {
// 3-16 chars, alphanumeric and underscore, must start with letter
return username.matches("^[a-zA-Z][a-zA-Z0-9_]{2,15}$");
}
public static boolean isValidEmail(String email) {
// Basic email pattern
return email.matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");
}
public static boolean isValidPhone(String phone) {
// Format: (123) 456-7890 or 123-456-7890
return phone.matches("^(\\(\\d{3}\\)\\s?|\\d{3}-)\\d{3}-\\d{4}$");
}
public static boolean isStrongPassword(String password) {
// At least 8 chars, with uppercase, lowercase, and digit
boolean hasLength = password.length() >= 8;
boolean hasUpper = password.matches(".*[A-Z].*");
boolean hasLower = password.matches(".*[a-z].*");
boolean hasDigit = password.matches(".*\\d.*");
return hasLength && hasUpper && hasLower && hasDigit;
}
public static boolean isValidURL(String url) {
return url.matches("^https?://[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}.*$");
}
public static boolean isValidDate(String date) {
return date.matches("^\\d{4}-\\d{2}-\\d{2}$");
}
public static void main(String[] args) {
// Usernames
String[] usernames = {"alice", "bob123", "a", "user_name", "123user"};
System.out.println("Usernames:");
for (String user : usernames) {
System.out.println(" " + user + ": " + isValidUsername(user));
}
// Emails
String[] emails = {"user@example.com", "invalid", "test@test.co.uk"};
System.out.println("\nEmails:");
for (String email : emails) {
System.out.println(" " + email + ": " + isValidEmail(email));
}
// Phones
String[] phones = {"(555) 123-4567", "555-123-4567", "5551234567"};
System.out.println("\nPhones:");
for (String phone : phones) {
System.out.println(" " + phone + ": " + isValidPhone(phone));
}
// Passwords
String[] passwords = {"weak", "Strong123", "nodigits", "NOCAPS123"};
System.out.println("\nPasswords:");
for (String pwd : passwords) {
System.out.println(" " + pwd + ": " + isStrongPassword(pwd));
}
// URLs
String[] urls = {"https://example.com", "http://test.org/path", "invalid"};
System.out.println("\nURLs:");
for (String url : urls) {
System.out.println(" " + url + ": " + isValidURL(url));
}
// Dates
String[] dates = {"2025-01-29", "2025-1-9", "01/29/2025"};
System.out.println("\nDates:");
for (String date : dates) {
System.out.println(" " + date + ": " + isValidDate(date));
}
}
}
Exercise: Practical.java
Validate that a username contains only letters, numbers, and underscores, and is 3-16 characters long