Java Regular Expressions
Java - Regular Expressions
Section titled “Java - Regular Expressions”Regular expressions (regex) are sequences of characters that define a search pattern. They are powerful tools for pattern matching, searching, and manipulating text.
Java provides the java.util.regex package for working with regular expressions. Its syntax is largely compatible with Perl.
Core Classes:
Section titled “Core Classes:”PatternClass: Represents a compiled regular expression. Compiling a pattern is often the first step and can be computationally intensive, so it’s efficient to compile patterns once if they are reused.Patternobjects are immutable and thread-safe. You create aPatternusing the staticcompile()method:Pattern p = Pattern.compile(regexString);MatcherClass: An engine that performs matching operations on an input character sequence using aPattern. AMatcheris obtained by calling thematcher(input)method on aPatternobject:Matcher m = p.matcher(inputString);.Matcherobjects are stateful and not thread-safe.PatternSyntaxException: An unchecked exception thrown to indicate a syntax error in a regular expression pattern during compilation.
Basic Workflow:
Section titled “Basic Workflow:”- Define your regular expression as a String.
- Compile the regex String into a
Patternobject usingPattern.compile(). - Create a
Matcherobject from thePatternand your input text usingpattern.matcher(inputText). - Use
Matchermethods (likefind(),matches(),lookingAt(),group()) to perform matching operations and retrieve results.
Capturing Groups
Section titled “Capturing Groups”Parentheses () in a regex create capturing groups. They allow you to:
- Treat multiple characters as a single unit (e.g., for applying quantifiers like
*,+,?). - Extract specific parts of the matched text.
Groups are numbered starting from 1 based on their opening parenthesis from left to right. Group 0 always represents the entire match.
Example: Extracting Data with Groups
Section titled “Example: Extracting Data with Groups”import java.util.regex.Matcher;import java.util.regex.Pattern;
public class RegexGroupsDemo { public static void main(String[] args) { String text = "User: alice ID: 101, User: bob ID: 205"; // Regex to find 'User: (name)' and 'ID: (number)' // (\w+) captures the username (word characters) // (\d+) captures the ID (digits) String regex = "User: (\\w+) ID: (\\d+)";
Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(text);
// Use find() to locate matches within the text while (matcher.find()) { System.out.println("Full match (Group 0): " + matcher.group(0)); System.out.println("Username (Group 1): " + matcher.group(1)); System.out.println("User ID (Group 2): " + matcher.group(2)); System.out.println("Start index: " + matcher.start() + ", End index: " + matcher.end()); System.out.println("---"); } }}Expected Output:
Full match (Group 0): User: alice ID: 101Username (Group 1): aliceUser ID (Group 2): 101Start index: 0, End index: 19---Full match (Group 0): User: bob ID: 205Username (Group 1): bobUser ID (Group 2): 205Start index: 21, End index: 38---You can find the number of capturing groups using matcher.groupCount() (which excludes group 0).
Regular Expression Syntax Quick Reference:
Section titled “Regular Expression Syntax Quick Reference:”Common metacharacters and constructs:
| Syntax | Description |
|---|---|
. | Any single character (except newline unless DOTALL flag is set) |
^ | Beginning of the line (or string with MULTILINE flag) |
$ | End of the line (or string with MULTILINE flag) |
[...] | Character class: Matches any single character inside the brackets (e.g., [abc]) |
[^...] | Negated character class: Matches any single character not inside (e.g., [^0-9]) |
A|B | Alternation: Matches either A or B |
(...) | Capturing group |
(?:...) | Non-capturing group (groups characters but doesn’t capture) |
\d | A digit: [0-9] |
\D | A non-digit: [^0-9] |
\s | A whitespace character: [ \t\n\x0B\f\r] |
\S | A non-whitespace character |
\w | A word character: [a-zA-Z_0-9] |
\W | A non-word character |
\b | Word boundary |
\B | Non-word boundary |
* | Quantifier: Zero or more occurrences of the preceding element |
+ | Quantifier: One or more occurrences |
? | Quantifier: Zero or one occurrence |
{n} | Quantifier: Exactly n occurrences |
{n,} | Quantifier: At least n occurrences |
{n,m} | Quantifier: At least n but not more than m occurrences |
*?, +?, ??, {n,}? etc. | Lazy/Reluctant quantifiers: Match the shortest possible string |
Note: Backslashes (\) need to be escaped within Java String literals (e.g., \d becomes "\\d").
Key Matcher Methods:
Section titled “Key Matcher Methods:”Methods for Finding Matches:
Section titled “Methods for Finding Matches:”| Method | Description |
|---|---|
boolean find() | Attempts to find the next subsequence of the input that matches the pattern. Returns true if found, false otherwise. Often used in a while loop. |
boolean find(int start) | Resets the matcher and searches starting from the specified index. |
boolean matches() | Attempts to match the entire input sequence against the pattern. Returns true only if the whole input matches. |
boolean lookingAt() | Attempts to match the pattern starting from the beginning of the input sequence. Doesn’t require the entire input to match. |
Methods for Retrieving Match Information:
Section titled “Methods for Retrieving Match Information:”| Method | Description |
|---|---|
String group() or String group(0) | Returns the input subsequence matched by the previous match (the entire match). |
String group(int group) | Returns the subsequence captured by the given group number during the previous match. |
String group(String name) | Returns the subsequence captured by the given named group (?<name>...). |
int groupCount() | Returns the number of capturing groups in the pattern (excluding group 0). |
int start() or int start(0) | Returns the start index of the previous match. |
int start(int group) | Returns the start index of the subsequence captured by the given group. |
int end() or int end(0) | Returns the offset after the last character of the previous match. |
int end(int group) | Returns the offset after the last character captured by the given group. |
Methods for Replacing Text:
Section titled “Methods for Replacing Text:”| Method | Description |
|---|---|
String replaceAll(String replacement) | Replaces every subsequence of the input that matches the pattern with the replacement string. |
String replaceFirst(String replacement) | Replaces only the first subsequence that matches the pattern. |
Matcher appendReplacement(StringBuffer sb, String replacement) or Matcher appendReplacement(StringBuilder sb, String replacement) | Appends the text preceding the current match and the replacement text to the given buffer. Allows complex replacements, including using captured groups ($1, $2, etc.) in the replacement string. |
StringBuffer appendTail(StringBuffer sb) or StringBuilder appendTail(StringBuilder sb) | Appends the remainder of the input sequence (after the last match) to the buffer. Typically used after a loop with appendReplacement. |
Example: replaceAll and replaceFirst
Section titled “Example: replaceAll and replaceFirst”import java.util.regex.Matcher;import java.util.regex.Pattern;
public class RegexReplaceDemo { private static final String REGEX = "\b(cat|dog|fish)\b"; // Match whole words: cat, dog, or fish private static final String INPUT = "The quick brown fox jumps over the lazy dog. The cat naps."; private static final String REPLACE_ALL = "animal"; private static final String REPLACE_FIRST = "pet";
public static void main(String[] args) { Pattern p = Pattern.compile(REGEX); Matcher m = p.matcher(INPUT);
// Replace all occurrences String resultAll = m.replaceAll(REPLACE_ALL); System.out.println("Replace All: " + resultAll);
// Replace only the first occurrence (need a new matcher or reset) m.reset(); // Reset the matcher to the beginning of the input String resultFirst = m.replaceFirst(REPLACE_FIRST); System.out.println("Replace First: " + resultFirst); }}Expected Output:
Replace All: The quick brown fox jumps over the lazy animal. The animal naps.Replace First: The quick brown fox jumps over the lazy pet. The cat naps.Example: appendReplacement and appendTail (Using StringBuilder)
Section titled “Example: appendReplacement and appendTail (Using StringBuilder)”import java.util.regex.Matcher;import java.util.regex.Pattern;
public class RegexAppendDemo { private static final String REGEX = "(John|Jane)"; private static final String INPUT = "John Doe met Jane Smith. John works hard."; private static final String REPLACE_FORMAT = "**$1**"; // $1 refers to the first captured group
public static void main(String[] args) { Pattern p = Pattern.compile(REGEX); Matcher m = p.matcher(INPUT); StringBuilder sb = new StringBuilder();
while (m.find()) { // Append text before the match and the replacement m.appendReplacement(sb, REPLACE_FORMAT); } // Append any remaining text after the last match m.appendTail(sb);
System.out.println(sb.toString()); }}Expected Output:
**John** Doe met **Jane** Smith. **John** works hard.Performance Considerations:
Section titled “Performance Considerations:”- Compile Once, Reuse: Compiling a
Patternis expensive. If you use the same regex multiple times, compile it once and reuse thePatternobject. - Avoid Complex Regex in Hot Loops: Very complex patterns or inefficiently written regex can significantly impact performance.
- Consider Alternatives: For simple substring searching or splitting, standard String methods (
contains(),indexOf(),split()) might be faster than regex.