正則表達式是一種用于匹配字符串的模式,在許多編程語言中廣泛使用。Java 正則表達式提供了強大的文本處理能力,能夠對字符串進行查找、替換、分割等操作。
一、正則表達式的基本語法
正則表達式由普通字符和特殊字符組成。普通字符包括字母、數字和標點符號,而特殊字符(也稱為元字符)則具有特殊意義,用于構建復雜的匹配模式。
1.1 普通字符
普通字符匹配自身。例如,正則表達式 abc
匹配字符串 "abc"
。
1.2 元字符
元字符是正則表達式的核心部分,用于定義復雜的匹配模式。常見的元字符包括:
.
:匹配任意一個字符(除換行符)。^
:匹配字符串的開始。$
:匹配字符串的結束。*
:匹配前一個字符零次或多次。+
:匹配前一個字符一次或多次。?
:匹配前一個字符零次或一次。[]
:定義字符類,匹配其中任意一個字符。|
:表示“或”操作。()
:用于分組和捕獲。{}
:用于限定重復次數。
1.3 轉義字符
有些字符在正則表達式中有特殊意義,如果要匹配這些字符本身,需要使用反斜杠 \
進行轉義。例如,要匹配字符 .
,應使用 \.
。
1.4 字符類
字符類用于定義一個字符集合,匹配其中任意一個字符。常用的字符類包括:
[abc]
:匹配字符a
、b
或c
。[a-z]
:匹配任意一個小寫字母。[A-Z]
:匹配任意一個大寫字母。[0-9]
:匹配任意一個數字。[^abc]
:匹配除a
、b
、c
之外的任意一個字符。
1.5 預定義字符類
預定義字符類是一些常用字符類的簡寫形式,包括:
\d
:匹配一個數字,等價于[0-9]
。\D
:匹配一個非數字字符,等價于[^0-9]
。\w
:匹配一個單詞字符(字母、數字或下劃線),等價于[a-zA-Z0-9_]
。\W
:匹配一個非單詞字符,等價于[^a-zA-Z0-9_]
。\s
:匹配一個空白字符(空格、制表符、換行符等),等價于[ \t\n\x0B\f\r]
。\S
:匹配一個非空白字符,等價于[^ \t\n\x0B\f\r]
。
1.6 邊界匹配符
邊界匹配符用于匹配字符串中的邊界位置,包括:
\b
:匹配一個單詞邊界。\B
:匹配一個非單詞邊界。
1.7 限定符
限定符用于指定前一個字符或子模式的重復次數,包括:
*
:匹配前一個字符零次或多次。+
:匹配前一個字符一次或多次。?
:匹配前一個字符零次或一次。{n}
:匹配前一個字符恰好 n 次。{n,}
:匹配前一個字符至少 n 次。{n,m}
:匹配前一個字符至少 n 次,至多 m 次。
1.8 捕獲組和非捕獲組
捕獲組用于將匹配的子模式存儲起來,以便在后續操作中引用。非捕獲組用于對子模式進行分組,但不存儲匹配結果。
()
:捕獲組。(?:)
:非捕獲組。
1.9 零寬斷言
零寬斷言用于指定某個位置必須滿足的條件,包括:
(?=)
:正向先行斷言。(?!
:負向先行斷言。(?<=)
:正向后行斷言。(?<!
:負向后行斷言。
二、Java 中的正則表達式 API
Java 提供了 java.util.regex
包來支持正則表達式處理,其中最重要的類是 Pattern
和 Matcher
。
2.1 Pattern
類
Pattern
類表示一個正則表達式的編譯表示。常用的方法包括:
compile(String regex)
:編譯給定的正則表達式。matcher(CharSequence input)
:創建一個匹配器對象。
2.2 Matcher
類
Matcher
類用于對輸入字符串進行模式匹配操作。常用的方法包括:
matches()
:整個字符串是否與正則表達式匹配。find()
:是否找到與正則表達式匹配的子字符串。group()
:返回前一次匹配的子字符串。replaceAll(String replacement)
:替換所有匹配的子字符串。replaceFirst(String replacement)
:替換第一個匹配的子字符串。lookingAt()
:是否從字符串的開頭開始匹配。
三、Java 正則表達式的常見用法
3.1 字符串匹配
3.1.1 完全匹配
要判斷字符串是否完全匹配某個正則表達式,可以使用 Pattern
和 Matcher
類:
String regex = "\\d+";
String input = "12345";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
boolean isMatch = matcher.matches();
System.out.println("完全匹配: " + isMatch);
3.1.2 子字符串匹配
要判斷字符串中是否包含某個正則表達式匹配的子字符串,可以使用 find
方法:
String regex = "\\d+";
String input = "hello 12345 world";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
boolean found = matcher.find();
System.out.println("包含子字符串匹配: " + found);
3.2 字符串替換
正則表達式可以用于替換字符串中的匹配部分。replaceAll
和 replaceFirst
方法用于替換所有匹配的子字符串或第一個匹配的子字符串:
String regex = "\\d+";
String input = "hello 12345 world";
String replacement = "number";
String result = input.replaceAll(regex, replacement);
System.out.println("替換結果: " + result);
3.3 字符串分割
正則表達式可以用于根據模式分割字符串。String
類提供了 split
方法:
String regex = "\\s+";
String input = "hello world java";
String[] parts = input.split(regex);
System.out.println("分割結果: " + Arrays.toString(parts));
3.4 捕獲組
捕獲組用于將匹配的子模式存儲起來,以便在后續操作中引用。可以使用 group
方法獲取捕獲組的內容:
String regex = "(\\d{3})-(\\d{2})-(\\d{4})";
String input = "123-45-6789";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
if (matcher.matches()) {String part1 = matcher.group(1);String part2 = matcher.group(2);String part3 = matcher.group(3);System.out.println("捕獲組: " + part1 + ", " + part2 + ", " + part3);
}
3.5 零寬斷言
零寬斷言用于指定某個位置必須滿足的條件,但不包括在匹配結果中。以下示例展示了正向先行斷言:
String regex = "foo(?=bar)";
String input = "foobar";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
while (matcher.find()) {System.out.println("零寬斷言匹配: " + matcher.group());
}
四、Java 正則表達式高級應用
4.1 動態構建正則表達式
有時我們需要根據不同的輸入動態構建正則表達式。可以使用 StringBuilder
來拼接正則表達式:
String basePattern = "\\d";
int minDigits = 2;
int maxDigits = 4;
StringBuilder regex = new StringBuilder(basePattern);
regex.append("{").append(minDigits).append(",").append(maxDigits).append("}");
Pattern pattern = Pattern.compile(regex.toString());
String input = "123";
Matcher matcher = pattern.matcher(input);
boolean isMatch = matcher.matches();
System.out.println("動態構建正則表達式匹配: " + isMatch);
4.2 正則表達式中的嵌套組
嵌套組用于在一個捕獲組內再嵌套另一個捕獲組,以下示例展示了嵌套組的用法:
String regex = "(\\d{2})((\\d{2}))";
String input = "1234";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
if (matcher.matches()) {String outerGroup = matcher.group(1);String nestedGroup = matcher.group(2);String innermostGroup = matcher.group(3);System.out.println("外部組: " + outerGroup + ", 嵌套組: " + nestedGroup + ", 最內部組: " + innermostGroup);
}
4.3 分組命名和引用
Java 7 引入了分組命名功能,可以給捕獲組命名,并通過名字引用:
String regex = "(?<areaCode>\\d{3})-(?<prefix>\\d{3})-(?<lineNumber>\\d{4})";
String input = "123-456-7890";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
if (matcher.matches()) {String areaCode = matcher.group("areaCode");String prefix = matcher.group("prefix");String lineNumber = matcher.group("lineNumber");System.out.println("命名捕獲組: " + areaCode + ", " + prefix + ", " + lineNumber);
}
4.4 正則表達式的性能優化
在處理大型文本或復雜模式時,正則表達式的性能可能成為瓶頸。以下是一些性能優化建議:
- 避免回溯:盡量避免使用可能導致大量回溯的模式,如重復的捕獲組。
- 預編譯正則表達式:將正則表達式編譯為
Pattern
對象,并重用該對象,而不是每次都重新編譯。 - 使用非捕獲組:在不需要捕獲匹配內容時,使用非捕獲組
(?:)
代替捕獲組()
。
4.5 正則表達式調試
調試正則表達式可能比較困難,可以使用在線工具(如 regex101)或集成開發環境(IDE)中的正則表達式調試功能來幫助理解和測試正則表達式。
掌握正則表達式可以大大提高文本處理的效率和靈活性,Java 提供的正則表達式 API 使得在程序中使用正則表達式變得簡單高效。
黑馬程序員免費預約咨詢