PYnative

Python Programming

  • Learn Python ▼
    • Python Tutorials
    • Python Basics
    • Python Interview Q&As
  • Exercises ▼
    • Python Exercises
    • C++ Exercises
    • C Programming Exercises
    • Java Exercises
    • C# Exercises
  • Quizzes
  • Online Compilers▼
    • Online Python Code Editor
    • Online C Compiler
    • Online C++ Compiler
    • Online Java Compiler
    • Online C# Compiler
Home » Java Exercises » Java Regex Exercises: 30 Coding Problems with Solutions

Java Regex Exercises: 30 Coding Problems with Solutions

Updated on: July 6, 2026 | Leave a Comment

This collection of 30 Java regex exercises builds your pattern-matching skills from simple literal matches all the way to lookaheads, lookbehinds, and backreferences.

  • Early exercises cover character classes, quantifiers, anchors, and word boundaries
  • The middle set validates real-world formats like dates, times, hex colors, IP addresses, and phone numbers using capturing groups.
  • The final exercises tackle non-greedy matching, negative lookahead, CamelCase splitting, password strength validation, and inserting thousands separators with zero-width assertions.

Each exercise includes a Problem Statement, Purpose, Hint, and a Solution with Explanation.

  • Also, See: Java Exercises with over 20+ topic-wise sets and 575+ coding questions to practice.
  • Practice questions using our Online Java Compiler
+ Table of Contents (30 Exercises)

Table of contents

  • Exercise 1: Exact String Match
  • Exercise 2: Case-Insensitive Match
  • Exercise 3: Digits Only
  • Exercise 4: Alphanumeric Only
  • Exercise 5: Vowel Count
  • Exercise 6: No Digits
  • Exercise 7: Fixed Length Identifier
  • Exercise 8: Word Boundary
  • Exercise 9: Starts & Ends With
  • Exercise 10: Hex Color Code
  • Exercise 11: Whitespace Trimming
  • Exercise 12: Binary Number
  • Exercise 13: Variable Names
  • Exercise 14: Date Format (YYYY-MM-DD)
  • Exercise 15: Time Format (24-Hour)
  • Exercise 16: Extract Domain Name
  • Exercise 17: Duplicate Words
  • Exercise 18: MAC Address
  • Exercise 19: IP Address (IPv4)
  • Exercise 20: Phone Number Formatting
  • Exercise 21: HTML Tag Extractor
  • Exercise 22: CamelCase Splitter
  • Exercise 23: CSV Parser
  • Exercise 24: Password Strength
  • Exercise 25: Match Numbers NOT Followed by %
  • Exercise 26: Match Words NOT Starting with ‘un’
  • Exercise 27: Floating Point Numbers
  • Exercise 28: Remove Multi-line Comments
  • Exercise 29: Extract Email Components
  • Exercise 30: Thousands Separator

Exercise 1: Exact String Match

Problem Statement: Write a regex to match the exact word "Java" (case-sensitive).

Purpose: This exercise introduces the most basic form of a regex, a literal string, and shows that String.matches() compares against the entire input, not just a portion of it.

Given Input: testing "Java", "java", and "JAVA" against the pattern "Java"

Expected Output:

true
false
false
▼ Hint
  • A regex made only of plain letters matches those exact characters and nothing else.
  • Regex matching in Java is case-sensitive by default, so uppercase and lowercase letters are treated as completely different characters.
  • String.matches(regex) requires the entire string to match the pattern, not just part of it.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String regex = "Java";

        System.out.println("Java".matches(regex));
        System.out.println("java".matches(regex));
        System.out.println("JAVA".matches(regex));
    }
}Code language: Java (java)

Explanation:

  • String regex = "Java": A literal pattern with no special regex syntax at all. It matches only the exact sequence of characters J, a, v, a.
  • "Java".matches(regex): Returns true since the input is character-for-character identical to the pattern.
  • "java".matches(regex) and "JAVA".matches(regex): Both return false, since regex matching distinguishes between uppercase and lowercase letters unless told otherwise.
  • Whole-string matching: matches() implicitly anchors the pattern to both the start and end of the input, unlike some other regex methods that only look for a match anywhere inside the string.

Exercise 2: Case-Insensitive Match

Problem Statement: Match the word "java" regardless of case (e.g., Java, JAVA, JaVa).

Purpose: This exercise introduces the inline flag (?i), which switches a pattern into case-insensitive mode without needing a separate compilation flag passed in code.

Given Input: testing "Java", "JAVA", and "JaVa" against the pattern "(?i)java"

Expected Output:

true
true
true
▼ Hint
  • Place (?i) at the very start of the pattern to enable case-insensitive matching for the rest of the regex.
  • This inline flag affects every letter that follows it in the pattern, not just the next character.
  • No changes are needed to the input strings themselves, only to the pattern.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String regex = "(?i)java";

        System.out.println("Java".matches(regex));
        System.out.println("JAVA".matches(regex));
        System.out.println("JaVa".matches(regex));
    }
}Code language: Java (java)

Explanation:

  • (?i): An inline flag that turns on case-insensitive matching for the remainder of the pattern, embedded directly in the regex string itself.
  • (?i)java: With the flag active, this pattern now matches java, Java, JAVA, and any other capitalization combination of the same four letters.
  • All three inputs return true: Since the flag ignores case entirely, the specific mix of uppercase and lowercase letters in each test string no longer matters.
  • Alternative: Pattern.compile("java", Pattern.CASE_INSENSITIVE) achieves the same result using a compiled Pattern object and an explicit flag constant instead of the inline syntax.

Exercise 3: Digits Only

Problem Statement: Validate a string that contains exactly 5 digits (e.g., a US zip code like 90210).

Purpose: This exercise introduces the \d shorthand character class for digits, combined with a quantifier that requires an exact repeat count.

Given Input: testing "90210", "9021", and "902100" against the pattern "\\d{5}"

Expected Output:

true
false
false
▼ Hint
  • \d is a shorthand character class that matches any single digit from 0 to 9.
  • In a Java string literal, the backslash must itself be escaped, so the pattern is written as "\\d".
  • The {5} quantifier requires exactly 5 repetitions of whatever comes immediately before it.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String regex = "\\d{5}";

        System.out.println("90210".matches(regex));
        System.out.println("9021".matches(regex));
        System.out.println("902100".matches(regex));
    }
}Code language: Java (java)

Explanation:

  • \\d: In the Java string literal, this represents the single regex token \d, which matches any one digit character.
  • {5}: An exact-count quantifier, requiring precisely 5 digits in a row, no more and no fewer.
  • "9021".matches(regex): Returns false because the string only has 4 digits, one short of the required count.
  • "902100".matches(regex): Returns false because the string has 6 digits, one too many, since matches() requires the entire string to satisfy the pattern.

Exercise 4: Alphanumeric Only

Problem Statement: Check if a string contains only alphanumeric characters (letters and numbers) and no spaces or special characters.

Purpose: This exercise introduces a custom character class built with square brackets, combining letter ranges and digit ranges into one set of allowed characters.

Given Input: testing "Java123", "Java 123", and "Java_123" against the pattern "[a-zA-Z0-9]+"

Expected Output:

true
false
false
▼ Hint
  • Square brackets define a character class, a set of characters where any single one of them counts as a match.
  • A hyphen inside a character class, like a-z, defines a range rather than a literal hyphen character.
  • The + quantifier after the character class requires one or more matching characters across the whole string.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String regex = "[a-zA-Z0-9]+";

        System.out.println("Java123".matches(regex));
        System.out.println("Java 123".matches(regex));
        System.out.println("Java_123".matches(regex));
    }
}Code language: Java (java)

Explanation:

  • [a-zA-Z0-9]: A character class combining three ranges: lowercase letters, uppercase letters, and digits, so any single character from any of those three ranges counts as a match.
  • +: Requires the entire string to consist of one or more characters from that character class, with nothing else mixed in.
  • "Java 123".matches(regex): Returns false because the space character is not part of the allowed character class.
  • "Java_123".matches(regex): Returns false because the underscore is also outside the defined ranges, even though underscores are sometimes informally grouped with “alphanumeric” characters.

Exercise 5: Vowel Count

Problem Statement: Match any single English vowel (both lowercase and uppercase).

Purpose: This exercise introduces Pattern and Matcher together with a find() loop, the standard approach for locating every occurrence of a pattern inside a larger string, rather than checking the whole string at once.

Given Input: "Regular Expressions are Powerful", searched with the pattern "[AEIOUaeiou]"

Expected Output: Vowel count: 12

▼ Hint
  • List all ten vowel characters, both cases, inside a single character class.
  • Compile the pattern with Pattern.compile(), then create a Matcher for the input string with pattern.matcher(input).
  • Call find() repeatedly in a while loop. Each call advances to the next match, and it returns false once there are no more matches left.
▼ Solution & Explanation
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    public static void main(String[] args) {
        String regex = "[AEIOUaeiou]";
        String input = "Regular Expressions are Powerful";

        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);

        int count = 0;
        while (matcher.find()) {
            count++;
        }

        System.out.println("Vowel count: " + count);
    }
}Code language: Java (java)

Explanation:

  • [AEIOUaeiou]: A character class listing all five vowels in both uppercase and lowercase, so any single one of those ten characters counts as a match.
  • Pattern.compile(regex): Compiles the pattern once into a reusable Pattern object, which is more efficient than recompiling the same regex on every match attempt.
  • pattern.matcher(input): Creates a Matcher tied to this specific input string, ready to search through it for matches.
  • while (matcher.find()): Each call to find() locates the next vowel starting from wherever the previous match left off, letting the loop count every single vowel in the string.

Exercise 6: No Digits

Problem Statement: Match a string that contains absolutely no numeric digits.

Purpose: This exercise introduces a negated character class, which matches any character except the ones listed, the opposite approach from the earlier allow-list style character classes.

Given Input: testing "Hello World" and "Hello123" against the pattern "[^0-9]*"

Expected Output:

true
false
▼ Hint
  • A ^ as the very first character inside a character class negates it, meaning “match anything except these”.
  • [^0-9] matches any character that is not a digit from 0 to 9.
  • Use * rather than + if an empty string should also be considered a valid, digit-free match.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String regex = "[^0-9]*";

        System.out.println("Hello World".matches(regex));
        System.out.println("Hello123".matches(regex));
    }
}Code language: Java (java)

Explanation:

  • [^0-9]: The caret at the start of the character class inverts it, so this matches any character that is not one of the digits 0 through 9, including letters, spaces, and punctuation.
  • *: Allows zero or more of those non-digit characters, so the entire string is accepted as long as it never contains a digit anywhere.
  • "Hello World".matches(regex): Returns true, since letters and the space character are all outside the negated digit class.
  • "Hello123".matches(regex): Returns false, since the digits 1, 2, and 3 fall inside the excluded range, breaking the match for the whole string.
  • Alternative: "\\D*" uses the built-in shorthand for “non-digit” and behaves identically to the custom negated character class shown here.

Exercise 7: Fixed Length Identifier

Problem Statement: Match a string that starts with a letter followed by exactly 3 digits (e.g., A123, z987).

Purpose: This exercise combines two different pattern pieces back to back, a single-letter character class followed by a fixed-count digit group, showing how a regex is built from smaller, sequential building blocks.

Given Input: testing "A123", "z987", "AB123", and "A12" against the pattern "[A-Za-z]\\d{3}"

Expected Output:

true
true
false
false
▼ Hint
  • Start the pattern with a character class matching exactly one letter, upper or lowercase.
  • Follow it immediately with \d{3} to require exactly 3 digits right after that letter.
  • Since there is no quantifier on the letter class itself, it implicitly matches exactly one character.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String regex = "[A-Za-z]\\d{3}";

        System.out.println("A123".matches(regex));
        System.out.println("z987".matches(regex));
        System.out.println("AB123".matches(regex));
        System.out.println("A12".matches(regex));
    }
}Code language: Java (java)

Explanation:

  • [A-Za-z]: Matches exactly one letter, either uppercase or lowercase, since a character class with no quantifier always matches a single character.
  • \\d{3}: Immediately requires exactly 3 digits right after that letter, with no separator or gap allowed between them.
  • "AB123".matches(regex): Returns false because there are two letters at the start instead of one, which the pattern does not allow.
  • "A12".matches(regex): Returns false because only 2 digits follow the letter, one short of the required 3.

Exercise 8: Word Boundary

Problem Statement: Find the word "cat" only when it stands alone, not inside other words like "category" or "bobcat".

Purpose: This exercise introduces the \b word boundary anchor, which matches the invisible transition between a word character and a non-word character, without consuming any characters itself.

Given Input: "The cat sat near the category and the bobcat.", searched with the pattern "\\bcat\\b"

Expected Output: Match found at index: 4

▼ Hint
  • Place \b on both sides of cat to require a word boundary immediately before and after it.
  • A word boundary exists between a letter and a space, or between a letter and the very start or end of the string, but not between two letters.
  • Use matcher.start() inside a find() loop to report where each match begins in the original string.
▼ Solution & Explanation
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    public static void main(String[] args) {
        String regex = "\\bcat\\b";
        String input = "The cat sat near the category and the bobcat.";

        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);

        while (matcher.find()) {
            System.out.println("Match found at index: " + matcher.start());
        }
    }
}Code language: Java (java)

Explanation:

  • \\bcat\\b: Requires a word boundary immediately before the c and immediately after the second t, ensuring cat is not attached to any other letters on either side.
  • Why "category" does not match: Although it starts with cat, the character immediately after those three letters is e, another word character, so there is no word boundary there and the match fails.
  • Why "bobcat" does not match: The character immediately before cat is b, another word character, so there is no word boundary on that side either.
  • matcher.start(): Reports the index where the current match begins in the original string, which is 4 for the standalone "cat" in "The cat sat...".

Exercise 9: Starts & Ends With

Problem Statement: Check if a sentence starts with a capital letter and ends with a period (.).

Purpose: This exercise practices anchoring specific requirements to the beginning and end of a string, with a flexible middle section that can contain almost anything.

Given Input: testing "This is a sentence.", "this is a sentence.", and "This is a sentence" against the pattern "[A-Z].*\\."

Expected Output:

true
false
false
▼ Hint
  • Start the pattern with [A-Z] to require the very first character to be an uppercase letter.
  • Use .* in the middle to allow any number of any characters at all.
  • A period is a special regex character meaning “any character”, so a literal period at the end must be escaped as \..
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String regex = "[A-Z].*\\.";

        System.out.println("This is a sentence.".matches(regex));
        System.out.println("this is a sentence.".matches(regex));
        System.out.println("This is a sentence".matches(regex));
    }
}Code language: Java (java)

Explanation:

  • [A-Z]: Requires the first character of the string to be an uppercase letter, immediately ruling out sentences that start lowercase.
  • .*: Matches any sequence of characters, including none at all, filling the gap between the required first letter and the required final period.
  • \\.: Matches a literal period character. Without the backslash, a plain . in regex means “any character”, not specifically a period.
  • "This is a sentence".matches(regex): Returns false because the string has no trailing period at all, failing the final required character.

Exercise 10: Hex Color Code

Problem Statement: Validate a CSS hex color code (e.g., #FFF, #abc123, #12A4B6).

Purpose: This closing exercise combines a literal character, a character class, and grouped alternation, matching real-world CSS syntax that accepts either a 3-digit or a 6-digit hex code.

Given Input: testing "#FFF", "#abc123", "#12A4B6", "#12345", and "123456" against the pattern "#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})"

Expected Output:

true
true
true
false
false
▼ Hint
  • The pattern must start with a literal #, which is not a special regex character and needs no escaping.
  • Hex digits include both numbers and the letters A through F, so the character class needs 0-9, A-F, and a-f to cover both letter cases.
  • Use parentheses to group two alternatives separated by |, one requiring exactly 6 hex digits and the other requiring exactly 3.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String regex = "#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})";

        System.out.println("#FFF".matches(regex));
        System.out.println("#abc123".matches(regex));
        System.out.println("#12A4B6".matches(regex));
        System.out.println("#12345".matches(regex));
        System.out.println("123456".matches(regex));
    }
}Code language: Java (java)

Explanation:

  • #: Matched literally at the very start, requiring every valid input to begin with the hash symbol used in CSS hex color syntax.
  • ([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}): A group containing two alternatives joined by |, matching either exactly 6 hex digits or exactly 3, covering both the shorthand and full CSS hex formats.
  • "#12345".matches(regex): Returns false because 5 digits satisfies neither the 6-digit nor the 3-digit alternative.
  • "123456".matches(regex): Returns false because the string is missing the required leading #, even though the 6 hex digits themselves would otherwise be valid.

Exercise 11: Whitespace Trimming

Problem Statement: Match leading or trailing whitespaces in a string (useful for implementing a manual trim()).

Purpose: This exercise introduces the ^ and $ anchors combined with alternation, and uses replaceAll() to remove matched text rather than just checking whether a match exists.

Given Input: " Hello World "

Expected Output: "Hello World"

▼ Hint
  • \s matches any whitespace character, including spaces, tabs, and newlines.
  • ^\s+ matches one or more whitespace characters at the very start of the string, while \s+$ matches them at the very end.
  • Combine both with | so a single pattern covers leading and trailing whitespace, then pass it to replaceAll() with an empty replacement.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String input = "   Hello World   ";
        String regex = "^\\s+|\\s+$";

        String trimmed = input.replaceAll(regex, "");
        System.out.println("\"" + trimmed + "\"");
    }
}Code language: Java (java)

Explanation:

  • ^\\s+: Matches one or more whitespace characters anchored to the very beginning of the string.
  • \\s+$: Matches one or more whitespace characters anchored to the very end of the string.
  • |: Combines both alternatives, so replaceAll() strips matches from either end without touching whitespace in the middle of the string.
  • input.replaceAll(regex, ""): Replaces every match with an empty string, effectively deleting the leading and trailing whitespace while leaving the single space between Hello and World untouched.

Exercise 12: Binary Number

Problem Statement: Check if a string represents a valid binary number (contains only 0s and 1s).

Purpose: This exercise reinforces a simple character class restricted to just two characters, combined with the + quantifier to require at least one digit.

Given Input: testing "101010", "10102", and "" against the pattern "[01]+"

Expected Output:

true
false
false
▼ Hint
  • A character class listing only 0 and 1 restricts matches to just binary digits.
  • Use + rather than * so an empty string does not count as a valid binary number.
  • Any character outside the class, like the 2 in "10102", breaks the whole-string match.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String regex = "[01]+";

        System.out.println("101010".matches(regex));
        System.out.println("10102".matches(regex));
        System.out.println("".matches(regex));
    }
}Code language: Java (java)

Explanation:

  • [01]: A character class containing only two possible characters, 0 and 1, matching one binary digit at a time.
  • +: Requires at least one character from the class, so the whole string must consist entirely of 0s and 1s, with at least one digit present.
  • "10102".matches(regex): Returns false because the digit 2 falls outside the allowed character class.
  • "".matches(regex): Returns false because + requires at least one matching character, and an empty string has none.

Exercise 13: Variable Names

Problem Statement: Validate if a string is a valid Java variable identifier (starts with a letter, $, or _, followed by alphanumeric characters, $, or _).

Purpose: This exercise practices using two different character classes back to back, one for the restricted first character and a broader one for every character after it.

Given Input: testing "_count", "$value", "2ndPlace", and "user_Name1" against the pattern "[a-zA-Z_$][a-zA-Z0-9_$]*"

Expected Output:

true
true
false
true
▼ Hint
  • The first character class should exclude digits, since Java identifiers cannot start with a number.
  • The second character class, applied with *, can include digits along with letters, $, and _.
  • Using * rather than + on the second class allows single-character identifiers, since zero additional characters is also valid.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String regex = "[a-zA-Z_$][a-zA-Z0-9_$]*";

        System.out.println("_count".matches(regex));
        System.out.println("$value".matches(regex));
        System.out.println("2ndPlace".matches(regex));
        System.out.println("user_Name1".matches(regex));
    }
}Code language: Java (java)

Explanation:

  • [a-zA-Z_$]: Matches exactly one character for the required first position, restricted to letters, underscore, or dollar sign, deliberately excluding digits.
  • [a-zA-Z0-9_$]*: Matches zero or more characters for everything after the first position, this time including digits as well.
  • "2ndPlace".matches(regex): Returns false because the very first character is a digit, which the first character class does not permit.
  • "user_Name1".matches(regex): Returns true, since it starts with a letter and every character after that, including the underscore and trailing digit, falls within the second, broader character class.

Exercise 14: Date Format (YYYY-MM-DD)

Problem Statement: Match a date in the YYYY-MM-DD format (basic digit checking, e.g., 2026-12-31).

Purpose: This exercise practices combining fixed-length digit groups with literal separator characters, a common shape for structured identifiers like dates, without yet validating the actual calendar values.

Given Input: testing "2026-12-31", "26-12-31", and "2026/12/31" against the pattern "\\d{4}-\\d{2}-\\d{2}"

Expected Output:

true
false
false
▼ Hint
  • Break the pattern into three digit groups matching the year, month, and day segments.
  • The hyphen between digit groups is a literal character here, not a regex range, since it sits outside any square brackets.
  • This basic version only checks digit counts and separators. It does not verify that the month is between 01 and 12 or that the day is valid for that month.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String regex = "\\d{4}-\\d{2}-\\d{2}";

        System.out.println("2026-12-31".matches(regex));
        System.out.println("26-12-31".matches(regex));
        System.out.println("2026/12/31".matches(regex));
    }
}Code language: Java (java)

Explanation:

  • \\d{4}: Matches exactly 4 digits for the year portion.
  • -\\d{2}-\\d{2}: Matches a literal hyphen, exactly 2 digits for the month, another literal hyphen, and exactly 2 digits for the day.
  • "26-12-31".matches(regex): Returns false because the year portion only has 2 digits instead of the required 4.
  • "2026/12/31".matches(regex): Returns false because the separators are forward slashes rather than the literal hyphens the pattern requires.

Exercise 15: Time Format (24-Hour)

Problem Statement: Match a 24-hour time format string like 14:30 or 09:15 (assume hours 00-23 and minutes 00-59).

Purpose: This exercise practices real range validation using alternation, going beyond a simple digit count to actually restrict which numeric ranges are valid.

Given Input: testing "14:30", "09:15", "24:00", and "13:65" against the pattern "([01]\\d|2[0-3]):[0-5]\\d"

Expected Output:

true
true
false
false
▼ Hint
  • Valid hours split naturally into two ranges: 00–19 and 20–23, which need separate alternatives since a single digit range cannot express both.
  • [01]\d covers hours 00 through 19, while 2[0-3] covers hours 20 through 23.
  • Minutes are simpler, since every valid value from 00 to 59 shares the same first-digit range of 0 through 5.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String regex = "([01]\\d|2[0-3]):[0-5]\\d";

        System.out.println("14:30".matches(regex));
        System.out.println("09:15".matches(regex));
        System.out.println("24:00".matches(regex));
        System.out.println("13:65".matches(regex));
    }
}Code language: Java (java)

Explanation:

  • ([01]\\d|2[0-3]): A grouped alternative for the hour portion. The first branch, [01]\d, covers 00 through 19, and the second branch, 2[0-3], covers 20 through 23.
  • :[0-5]\\d: Requires a literal colon, followed by minutes restricted to 00 through 59, since the first minute digit can only range from 0 to 5.
  • "24:00".matches(regex): Returns false because 24 is not covered by either hour alternative, correctly rejecting an hour value that does not exist on a 24-hour clock.
  • "13:65".matches(regex): Returns false because 65 is outside the valid 00–59 minute range, even though the hour portion, 13, is perfectly valid.

Exercise 16: Extract Domain Name

Problem Statement: Extract the domain name from a URL (e.g., extract google.com from https://www.google.com/search).

Purpose: This exercise introduces capturing groups, using parentheses to isolate and extract just one meaningful part of a larger match, rather than matching or rejecting the whole string.

Given Input: "https://www.google.com/search"

Expected Output: Domain: google.com

▼ Hint
  • Match the protocol first with something like https?://, where the ? makes the s in https optional so both http and https match.
  • Use a non-capturing group, (?:www\.)?, to optionally skip over a leading www. without including it in the captured result.
  • Wrap the actual domain portion in parentheses to capture it, then retrieve it afterward with matcher.group(1).
▼ Solution & Explanation
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    public static void main(String[] args) {
        String regex = "https?://(?:www\\.)?([a-zA-Z0-9.-]+)";
        String url = "https://www.google.com/search";

        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(url);

        if (matcher.find()) {
            System.out.println("Domain: " + matcher.group(1));
        }
    }
}Code language: Java (java)

Explanation:

  • https?://: Matches either http:// or https://, since the ? makes the preceding s optional.
  • (?:www\\.)?: A non-capturing group, marked by ?:, that optionally matches a leading www. without that text becoming part of any captured group.
  • ([a-zA-Z0-9.-]+): A capturing group, marked by plain parentheses, matching the actual domain name made of letters, digits, dots, and hyphens.
  • matcher.group(1): Retrieves the text captured by the first parenthesized group, which is exactly the domain portion, separate from the protocol, the optional www., and the trailing /search path.

Exercise 17: Duplicate Words

Problem Statement: Find duplicate, consecutive words in a sentence (e.g., "The the movie was great").

Purpose: This exercise introduces backreferences, which let a pattern refer back to text captured earlier in the same match, essential for detecting repetition rather than a fixed literal value.

Given Input: "The the movie was was great"

Expected Output:

Duplicate found: The
Duplicate found: was
▼ Hint
  • Capture a word with (\w+), then require the exact same text again using the backreference \1.
  • Allow one or more whitespace characters between the two occurrences with \s+.
  • Compile the pattern with Pattern.CASE_INSENSITIVE so a capitalized word at the start of a sentence still matches its lowercase repeat.
▼ Solution & Explanation
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    public static void main(String[] args) {
        String regex = "\\b(\\w+)\\s+\\1\\b";
        String input = "The the movie was was great";

        Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(input);

        while (matcher.find()) {
            System.out.println("Duplicate found: " + matcher.group(1));
        }
    }
}Code language: Java (java)

Explanation:

  • (\\w+): Captures one or more word characters as the first group, representing whatever word is found first.
  • \\1: A backreference to the first captured group, requiring the exact same text to appear again, not just any word.
  • Pattern.CASE_INSENSITIVE: Lets "The" and "the" count as the same repeated word, even though they differ in capitalization.
  • Two separate matches: find() locates "The the" first, then continues scanning from where that match ended and locates "was was" as a second, independent match.

Exercise 18: MAC Address

Problem Statement: Validate a standard MAC address (e.g., 01:23:45:67:89:ab or A1-B2-C3-D4-E5-F6).

Purpose: This exercise combines a repeated group with an exact count quantifier, matching a structured, multi-segment identifier that can use either of two different separator characters.

Given Input: testing "01:23:45:67:89:ab", "A1-B2-C3-D4-E5-F6", "01:23:45:67:89", and "01:23:45:67:89:gh" against the pattern "([0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}"

Expected Output:

true
true
false
false
▼ Hint
  • A MAC address is 6 pairs of hex digits, separated by either a colon or a hyphen.
  • Group one hex pair plus its trailing separator together, then repeat that group exactly 5 times with {5}.
  • The final, sixth hex pair has no trailing separator, so it needs to be matched separately after the repeated group.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String regex = "([0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}";

        System.out.println("01:23:45:67:89:ab".matches(regex));
        System.out.println("A1-B2-C3-D4-E5-F6".matches(regex));
        System.out.println("01:23:45:67:89".matches(regex));
        System.out.println("01:23:45:67:89:gh".matches(regex));
    }
}Code language: Java (java)

Explanation:

  • ([0-9A-Fa-f]{2}[:-]): A group matching exactly 2 hex digits followed by either a colon or a hyphen.
  • {5}: Repeats that entire group exactly 5 times, accounting for the first 5 hex pairs and their trailing separators.
  • [0-9A-Fa-f]{2}: Matches the final, sixth hex pair on its own, with no trailing separator required after it.
  • "01:23:45:67:89:gh".matches(regex): Returns false because g and h are not valid hex digits, falling outside the 0-9A-Fa-f range.

Exercise 19: IP Address (IPv4)

Problem Statement: Validate a standard IPv4 address (ensure each octet is between 0 and 255).

Purpose: This exercise practices real numeric range validation across a repeated structure, building a reusable sub-pattern for one octet and then combining four of them with literal dot separators.

Given Input: testing "192.168.1.1", "255.255.255.255", "256.100.50.25", and "192.168.1"

Expected Output:

true
true
false
false
▼ Hint
  • Build a single sub-pattern for “one valid octet” first, covering 250–255, 200–249, and 0–199 as three separate alternatives.
  • Reuse that same sub-pattern string four times, joined by literal, escaped dots.
  • Building the full pattern by concatenating a repeated substring in code keeps the regex far more readable than writing it out by hand four times.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String octet = "(25[0-5]|2[0-4]\\d|[01]?\\d?\\d)";
        String regex = octet + "\\." + octet + "\\." + octet + "\\." + octet;

        System.out.println("192.168.1.1".matches(regex));
        System.out.println("255.255.255.255".matches(regex));
        System.out.println("256.100.50.25".matches(regex));
        System.out.println("192.168.1".matches(regex));
    }
}Code language: Java (java)

Explanation:

  • 25[0-5]: The first alternative in the octet pattern, covering 250 through 255.
  • 2[0-4]\\d: The second alternative, covering 200 through 249.
  • [01]?\\d?\\d: The third alternative, covering everything from 0 through 199, including single and double digit values.
  • Building the full pattern in code: Concatenating the octet string four times with escaped dots keeps the final regex readable, avoiding a single massive, repeated block of near-identical alternation written out by hand.
  • "256.100.50.25".matches(regex): Returns false because 256 exceeds the maximum valid octet value of 255, and none of the three alternatives accept it.

Exercise 20: Phone Number Formatting

Problem Statement: Match and group a 10-digit US phone number into 3 groups: area code, prefix, and line number (e.g., (123) 456-7890 or 123-456-7890).

Purpose: This closing exercise combines optional literal characters with multiple capturing groups, extracting structured pieces out of a phone number regardless of which common formatting style was used.

Given Input: "(123) 456-7890" and "123-456-7890"

Expected Output:

Area: 123, Prefix: 456, Line: 7890
Area: 123, Prefix: 456, Line: 7890
▼ Hint
  • Make the parentheses around the area code optional with \(? and \)?, since not every format includes them.
  • Allow an optional separator, such as a space, hyphen, or dot, between each group using a character class with a ? quantifier.
  • Wrap each group of digits, the area code, prefix, and line number, in its own capturing parentheses so they can be retrieved individually afterward.
▼ Solution & Explanation
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    public static void main(String[] args) {
        String regex = "\\(?(\\d{3})\\)?[-.\\s]?(\\d{3})[-.\\s]?(\\d{4})";

        String phone1 = "(123) 456-7890";
        String phone2 = "123-456-7890";

        Matcher matcher1 = Pattern.compile(regex).matcher(phone1);
        Matcher matcher2 = Pattern.compile(regex).matcher(phone2);

        if (matcher1.matches()) {
            System.out.println("Area: " + matcher1.group(1) + ", Prefix: " + matcher1.group(2) + ", Line: " + matcher1.group(3));
        }
        if (matcher2.matches()) {
            System.out.println("Area: " + matcher2.group(1) + ", Prefix: " + matcher2.group(2) + ", Line: " + matcher2.group(3));
        }
    }
}Code language: Java (java)

Explanation:

  • \\(?(\\d{3})\\)?: Matches an optional opening parenthesis, then captures exactly 3 digits as the area code, then an optional closing parenthesis.
  • [-.\\s]?: Matches an optional single separator character, either a hyphen, a dot, or any whitespace character, between each group of digits.
  • (\\d{3}) and (\\d{4}): Capture the 3-digit prefix and the 4-digit line number as two more separate groups, following the same digits-then-optional-separator pattern.
  • Same three groups, two formats: Both "(123) 456-7890" and "123-456-7890" produce identical captured groups, since the optional parentheses and flexible separator character class accommodate both styles with the same single pattern.

Exercise 21: HTML Tag Extractor

Problem Statement: Extract the text content sitting inside an HTML <h1> tag (e.g., extract "Hello" from <h1>Hello</h1>).

Purpose: This exercise introduces the reluctant (non-greedy) quantifier *?, which stops at the first possible match instead of consuming as much text as it can.

Given Input: "<h1>Hello</h1>"

Expected Output: Extracted text: Hello

▼ Hint
  • Match the literal opening tag, then capture the content, then match the literal closing tag.
  • Use (.*?) rather than (.*) for the captured content, so the match stops at the very first closing tag it finds.
  • This becomes important when a string contains more than one tag, since a greedy .* would stretch across everything up through the very last closing tag instead.
▼ Solution & Explanation
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    public static void main(String[] args) {
        String regex = "<h1>(.*?)</h1>";
        String input = "<h1>Hello</h1>";

        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);

        if (matcher.find()) {
            System.out.println("Extracted text: " + matcher.group(1));
        }
    }
}Code language: Java (java)

Explanation:

  • <h1> and </h1>: Matched literally, since angle brackets are not special regex characters and need no escaping.
  • (.*?): A reluctant quantifier that captures as few characters as possible while still allowing the rest of the pattern, the closing tag, to match.
  • matcher.group(1): Retrieves just the captured content between the two tags, excluding the tags themselves.
  • Caution: This simple approach breaks down on nested or malformed HTML. For any real HTML parsing task, a dedicated HTML parser library is far more reliable than a hand-written regex.

Exercise 22: CamelCase Splitter

Problem Statement: Write a regex to split a CamelCase string into separate words (e.g., turn camelCaseString into camel Case String).

Purpose: This exercise introduces a zero-width split point built entirely from lookaround assertions, splitting on a position in the string rather than on any actual character.

Given Input: "camelCaseString"

Expected Output: camel Case String

▼ Hint
  • Use a lookahead, (?=[A-Z]), to find every position immediately before an uppercase letter.
  • Add a negative lookbehind, (?<!^), to exclude the very first position in the string, since splitting there would produce an unwanted empty first element.
  • Pass the combined pattern to String.split(), then join the resulting array with spaces.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String input = "camelCaseString";
        String regex = "(?<!^)(?=[A-Z])";

        String[] words = input.split(regex);
        System.out.println(String.join(" ", words));
    }
}Code language: Java (java)

Explanation:

  • (?=[A-Z]): A positive lookahead marking every position in the string that is immediately followed by an uppercase letter, without consuming that letter.
  • (?<!^): A negative lookbehind excluding the very start of the string, so if the input itself began with an uppercase letter, that position would not trigger an extra split.
  • input.split(regex): Splits the string at each qualifying zero-width position, without consuming or removing any actual characters from the result.
  • String.join(" ", words): Reassembles the resulting word array into a single space-separated string for display.

Exercise 23: CSV Parser

Problem Statement: Match a line of comma-separated values, capturing each value while accounting for optional spaces around the commas.

Purpose: This exercise uses a regex as a splitting delimiter rather than a whole-string match, showing how split() can absorb surrounding whitespace along with the separator itself.

Given Input: "Java, Python , C++,Kotlin"

Expected Output:

[Java]
[Python]
[C++]
[Kotlin]
▼ Hint
  • Build a delimiter pattern that matches optional whitespace, then a comma, then more optional whitespace: \s*,\s*.
  • Pass that pattern directly to String.split() rather than splitting on a plain comma.
  • This approach naturally trims stray spaces around each value without a separate trim() call on every element.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String regex = "\\s*,\\s*";
        String input = "Java, Python , C++,Kotlin";

        String[] values = input.split(regex);
        for (String value : values) {
            System.out.println("[" + value + "]");
        }
    }
}Code language: Java (java)

Explanation:

  • \\s*,\\s*: Matches zero or more whitespace characters, then a literal comma, then zero or more whitespace characters again, treating the whole thing as one delimiter.
  • input.split(regex): Breaks the string apart everywhere that delimiter pattern occurs, discarding the matched commas and surrounding spaces entirely.
  • "Python " versus "Python": Without the surrounding \s*, splitting on a plain comma would leave a stray leading or trailing space on values like " Python ". The whitespace-aware delimiter avoids that entirely.
  • Square brackets in the output: Added purely for display, to make any accidental leftover whitespace in a value immediately visible around its printed brackets.

Exercise 24: Password Strength

Problem Statement: Validate a password that must be at least 8 characters long, contain at least one uppercase letter, one lowercase letter, one digit, and one special character.

Purpose: This exercise introduces stacking multiple lookaheads at the start of a pattern, a common technique for enforcing several independent conditions on the same string at once.

Given Input: testing "Passw0rd!", "password1", "PASSWORD1!", and "Pw1!"

Expected Output:

true
false
false
false
▼ Hint
  • Each requirement can be written as its own lookahead, like (?=.*[A-Z]) for “contains an uppercase letter somewhere”.
  • Since each lookahead is zero-width, they can all be stacked one after another at the very start of the pattern without consuming any characters.
  • After all the lookaheads, add .{8,} to actually consume and enforce the minimum overall length.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String regex = "(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[^a-zA-Z0-9]).{8,}";

        System.out.println("Passw0rd!".matches(regex));
        System.out.println("password1".matches(regex));
        System.out.println("PASSWORD1!".matches(regex));
        System.out.println("Pw1!".matches(regex));
    }
}Code language: Java (java)

Explanation:

  • (?=.*[a-z]): Requires a lowercase letter somewhere in the string, checked without moving the matching position forward.
  • (?=.*[A-Z]) and (?=.*\\d): Similarly require an uppercase letter and a digit somewhere in the string, each as its own independent condition.
  • (?=.*[^a-zA-Z0-9]): Requires at least one character that is not a letter or digit, covering punctuation and symbols as the “special character” requirement.
  • .{8,}: The only part of the pattern that actually consumes characters, requiring the whole string to be at least 8 characters long once every lookahead condition has already passed.

Exercise 25: Match Numbers NOT Followed by %

Problem Statement: Find all integers in a text that are not immediately followed by a percent sign (%).

Purpose: This exercise introduces negative lookahead for exclusion, and highlights a subtle pitfall: pairing it directly with a greedy quantifier can let the engine backtrack into a shorter, unintended partial match.

Given Input: "Sales grew 20% while profit rose 15 points and revenue hit 100"

Expected Output:

Found: 15
Found: 100
▼ Hint
  • A first attempt like \d+(?!%) looks reasonable, but the engine can backtrack \d+ down to a shorter run of digits just to satisfy the lookahead, corrupting numbers like 20% into a spurious partial match.
  • Add a second negative lookahead, (?!\d), right after \d+, forcing the engine to only consider positions where the full run of digits has actually ended.
  • Only after confirming the digit run is complete should the (?!%) check for a trailing percent sign be applied.
▼ Solution & Explanation
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    public static void main(String[] args) {
        String regex = "\\d+(?!\\d)(?!%)";
        String input = "Sales grew 20% while profit rose 15 points and revenue hit 100";

        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);

        while (matcher.find()) {
            System.out.println("Found: " + matcher.group());
        }
    }
}Code language: Java (java)

Explanation:

  • \\d+: Greedily matches as many consecutive digits as possible at the current position.
  • (?!\\d): Confirms the digit run truly ended here, meaning the next character is not another digit. This blocks the engine from backtracking to a shorter, incomplete number just to satisfy a later check.
  • (?!%): Only now checks whether a percent sign immediately follows the complete number, rejecting the whole match if it does.
  • Why 20 is skipped entirely, not partially matched: Since (?!\d) forces the engine to only consider the complete two-digit run, and that complete run is immediately followed by %, the entire match attempt at that position fails, rather than falling back to matching just 2.

Exercise 26: Match Words NOT Starting with ‘un’

Problem Statement: Find all words that do not begin with the prefix "un".

Purpose: This exercise applies a negative lookahead right after a word boundary, filtering out entire words based on how they start, rather than filtering individual characters.

Given Input: "The unhappy user was unable to undo the untimely mistake"

Expected Output:

The
user
was
to
the
mistake
▼ Hint
  • Start with \b to anchor the check to the beginning of each word.
  • Add (?!un) immediately after the boundary, rejecting any position where the next two characters are u followed by n.
  • Follow that with \w+\b to actually capture the rest of the word once the lookahead has passed.
▼ Solution & Explanation
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    public static void main(String[] args) {
        String regex = "\\b(?!un)\\w+\\b";
        String input = "The unhappy user was unable to undo the untimely mistake";

        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(input);

        while (matcher.find()) {
            System.out.println(matcher.group());
        }
    }
}Code language: Java (java)

Explanation:

  • \\b: Anchors the check to the start of a word, so the lookahead that follows only evaluates the first two characters of each word, not two characters found mid-word.
  • (?!un): Rejects the position entirely if the next two characters spell un, ruling out unhappy, unable, undo, and untimely right at their starting boundary.
  • \\w+\\b: Once a word survives the lookahead, this captures the rest of it, up through its own trailing word boundary.
  • Words like "user": Pass the lookahead cleanly, since their first two characters are us, not un, even though the word starts with the same letter u the excluded words do.

Exercise 27: Floating Point Numbers

Problem Statement: Match valid Java floating-point literals, including signs, decimals, and scientific notation (e.g., 3.14, -0.5, 6.022e23).

Purpose: This exercise combines optional signs, an optional decimal portion, and an entirely optional scientific notation suffix into one pattern, each piece marked with its own ? or wrapped in an optional group.

Given Input: testing "3.14", "-0.5", "6.022e23", and "abc"

Expected Output:

true
true
true
false
▼ Hint
  • Start with an optional sign, [-+]?, since a number may or may not have one.
  • Allow an optional whole-number part, an optional decimal point, and a required set of digits, since some valid numbers start directly with a dot.
  • Wrap the entire scientific notation suffix, the e or E, an optional sign, and its digits, in one group followed by ?, since a number is still valid without it.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String regex = "[-+]?\\d*\\.?\\d+([eE][-+]?\\d+)?";

        System.out.println("3.14".matches(regex));
        System.out.println("-0.5".matches(regex));
        System.out.println("6.022e23".matches(regex));
        System.out.println("abc".matches(regex));
    }
}Code language: Java (java)

Explanation:

  • [-+]?: Matches an optional leading sign, covering both positive and negative numbers, as well as numbers written with no sign at all.
  • \\d*\\.?\\d+: Matches an optional whole-number part, an optional decimal point, and a required final group of digits, covering both 3.14 and simpler whole numbers without a decimal point.
  • ([eE][-+]?\\d+)?: An entirely optional group for scientific notation, matching an e or E, an optional sign, and one or more digits for the exponent.
  • "6.022e23".matches(regex): Returns true, since the base number 6.022 is followed by a valid scientific notation suffix, e23, matching the optional final group.

Exercise 28: Remove Multi-line Comments

Problem Statement: Write a regex to find and remove Java multi-line comments (/* ... */).

Purpose: This exercise introduces the DOTALL mode, needed because the default behavior of . does not match newline characters, which would otherwise prevent matching a comment that spans multiple lines.

Given Input: "int x = 5; /* this is a\nmulti-line comment */ int y = 10;"

Expected Output: int x = 5; int y = 10;

▼ Hint
  • The literal /* and */ both contain a regex-special character, the asterisk, which must be escaped as \*.
  • Use a reluctant .*? between the two delimiters, so the match stops at the first */ rather than the last one in the string.
  • Add the inline flag (?s) at the start of the pattern so . also matches newline characters, letting the comment span multiple lines.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String code = "int x = 5; /* this is a\nmulti-line comment */ int y = 10;";
        String regex = "(?s)/\\*.*?\\*/";

        String cleaned = code.replaceAll(regex, "").trim();
        System.out.println(cleaned);
    }
}Code language: Java (java)

Explanation:

  • (?s): An inline flag enabling DOTALL mode, so the . in the pattern that follows also matches newline characters, not just ordinary characters.
  • /\\*.*?\\*/: Matches a literal /*, then reluctantly consumes everything up to the first */ it encounters, correctly handling the embedded newline in the middle of the comment.
  • code.replaceAll(regex, ""): Removes the entire matched comment, including its delimiters, replacing it with nothing.
  • Leftover double space: The final .trim() only removes whitespace from the very start and end of the whole string. It does not collapse the double space left behind in the middle where the comment used to sit.

Exercise 29: Extract Email Components

Problem Statement: Validate an email address and split it into three distinct capturing groups: username, domain, and TLD (Top-Level Domain).

Purpose: This exercise combines several character classes with three separate capturing groups, extracting a structured breakdown out of a single validated string in one pass.

Given Input: "john.doe@example.com"

Expected Output:

Username: john.doe
Domain: example
TLD: com
▼ Hint
  • Capture the username portion before the @ with a character class allowing letters, digits, dots, and a few common symbols.
  • Capture the domain portion after the @ but before the final dot separately from the TLD.
  • Require the TLD to be at least 2 letters, since real top-level domains like com or org are never shorter than that.
▼ Solution & Explanation
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Main {
    public static void main(String[] args) {
        String regex = "([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\\.([a-zA-Z]{2,})";
        String email = "john.doe@example.com";

        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(email);

        if (matcher.matches()) {
            System.out.println("Username: " + matcher.group(1));
            System.out.println("Domain: " + matcher.group(2));
            System.out.println("TLD: " + matcher.group(3));
        }
    }
}Code language: Java (java)

Explanation:

  • ([a-zA-Z0-9._%+-]+): The first capturing group, matching the username portion before the @ symbol, allowing letters, digits, and a handful of common punctuation characters.
  • ([a-zA-Z0-9.-]+): The second capturing group, matching the domain portion, up to but not including the final dot before the TLD.
  • \\.([a-zA-Z]{2,}): A literal dot followed by the third capturing group, requiring at least 2 letters for the TLD.
  • matcher.group(1), group(2), group(3): Retrieve the three captured pieces independently, giving john.doe, example, and com as three separate values from one single validated match.

Exercise 30: Thousands Separator

Problem Statement: Match positions in a long number string to insert commas as thousands separators (e.g., changing 1000000 to 1,000,000 using replaceAll).

Purpose: This closing exercise combines a positive lookbehind and a positive lookahead into a single zero-width insertion point, letting replaceAll() insert text at repeating positions without consuming or removing any digits.

Given Input: "1000000"

Expected Output: 1,000,000

▼ Hint
  • Use a positive lookbehind, (?<=\d), to require that a digit exists immediately before the insertion point.
  • Follow it with a positive lookahead requiring the remaining characters to consist of complete groups of exactly 3 digits, all the way to the end of the string.
  • Since both parts are zero-width assertions, replaceAll() can insert a comma at each matching position without deleting or duplicating any of the original digits.
▼ Solution & Explanation
public class Main {
    public static void main(String[] args) {
        String number = "1000000";
        String regex = "(?<=\\d)(?=(\\d{3})+(?!\\d))";

        String formatted = number.replaceAll(regex, ",");
        System.out.println(formatted);
    }
}Code language: Java (java)

Explanation:

  • (?<=\\d): A positive lookbehind requiring a digit immediately before the current position, ensuring commas are never inserted right at the very start of the number.
  • (?=(\\d{3})+(?!\\d)): A positive lookahead requiring that everything remaining from this position to the end of the string forms one or more complete groups of exactly 3 digits, with the inner (?!\d) confirming there is no leftover partial group afterward.
  • Zero-width match: Neither lookaround consumes any characters, so this pattern only ever matches an empty-width position, which replaceAll() then fills with a literal comma.
  • "1000000" becoming "1,000,000": Commas are inserted after the 1st and 4th digits, since those are exactly the positions where a digit precedes them and the remaining digits still form complete groups of 3.

Filed Under: Java Exercises

Did you find this page helpful? Let others know about it. Sharing helps me continue to create free Python resources.

TweetF  sharein  shareP  Pin

About Vishal

I’m Vishal Hule, the Founder of PYnative.com. As a Python developer, I enjoy assisting students, developers, and learners. Follow me on Twitter.

Related Tutorial Topics:

Java Exercises

All Coding Exercises:

C Exercises
C++ Exercises
Python Exercises
Java Exercises
C# Exercises

Python Exercises and Quizzes

Free coding exercises and quizzes cover Python basics, data structure, data analytics, and more.

  • 15+ Topic-specific Exercises and Quizzes
  • Each Exercise contains 25+ questions
  • Each Quiz contains 25 MCQ
Exercises
Quizzes

Leave a Reply Cancel reply

your email address will NOT be published. all comments are moderated according to our comment policy.

Use <pre> tag for posting code. E.g. <pre> Your entire code </pre>

In: Java Exercises
TweetF  sharein  shareP  Pin

  Java Exercises

  • All Java Exercises
  • Java Exercise for Beginners
  • Java Loops Exercise
  • Java String Exercise
  • Java ArrayList Exercise
  • Java LinkedList Exercise
  • Java HashMap and TreeMap Exercise
  • Java HashSet and TreeSet Exercise
  • Java OOP Exercise
  • Java Methods Exercise
  • Java Enums Exercise
  • Java Exception Handling Exercise
  • Java File Handling Exercise
  • Java Date and Time Exercise
  • Java Data Structures Exercise
  • Java Sorting and Searching Exercise
  • Java Lambda and Functional Interfaces Exercise
  • Java Regex Exercise
  • Java Random Data Generation Exercise
  • Java Generics Exercise
  • Java Reflection Exercise
  • Java JDBC Exercise

All Coding Exercises

Python Exercises C Exercises C++ Exercises Java Exercises C# Exercises

About PYnative

PYnative.com is for Python lovers. Here, You can get Tutorials, Exercises, and Quizzes to practice and improve your Python skills.

Follow Us

To get New Python Tutorials, Exercises, and Quizzes

  • Twitter
  • Facebook
  • Sitemap

Explore Python

  • Learn Python
  • Python Basics
  • Python Databases
  • Python Exercises
  • Python Quizzes
  • Online Python Code Editor
  • Python Tricks

Coding Exercises

  • C Exercises
  • C++ Exercises
  • Python Exercises
  • Java Exercises
  • C# Exercises

Legal Stuff

  • About Us
  • Contact Us

We use cookies to improve your experience. While using PYnative, you agree to have read and accepted our:

  • Terms Of Use
  • Privacy Policy
  • Cookie Policy

Copyright © 2018–2026 pynative.com