在 Java 中使用正規表示式過濾列表
一、簡介
在本教程中,我們將學習如何透過過濾與正規表示式 (regex) 相符的元素,從 Java 中的現有清單建立新清單。我們還將了解在 Java 中使用正規表示式過濾清單的各種方法。
2. 正規表示式概述
正規表示式是用於匹配字串中特定字元序列的模式。它們是令人難以置信的多功能工具,使我們能夠過濾、操作、替換和驗證文字。
Java 透過java.util.regex
套件提供了一組豐富的正規表示式功能。
2.1.常見特殊字符
我們使用一組特殊字元來建立匹配文字的模式。透過將這些字元組合為字串,我們建立正規表示式:
“.”
:匹配任何字元(換行符除外)“*”
:符合與前一個字元相同的字元的所有出現(零次或多次),即在“*”
之前“+”
:匹配與前一個字符相同的所有出現(一個或多個)的字符,即“+”
之前的字符“?”
:匹配零次或一次出現的前一個字符“^”
:匹配字串的開頭“$”
:匹配字串的結尾“[]”
:匹配方括號之間出現的任一個字符,例如, “[abc]”
匹配“a”
、 “b”
或“c”
“|”
:或運算,例如“a|b”
即“a”
或“b”
“()”
:用於分組
2.2.常見的正規表示式速記符號
為了引入轉義特殊字元結構,Java 中使用了反斜線“\”
。因此,我們使用兩個反斜杠,以便正確解釋一個反斜杠。
以下是常用模式的簡寫符號:
\\d
:匹配數字 ([0-9])\\w
:符合單字字元 ([a-zA-Z_0-9])\\s
:符合空白字元(空格、製表符、換行符)\\D
:符合任何非數字字符\\W
:符合任何非單字字符\\S
:符合任何非空白字符
3. 使用正規表示式在 Java 中過濾清單的不同方法
字串形式的正規表示式在內部編譯為確定性有限自動機 (DFA) 或非確定性有限自動機 (NFA)。匹配器使用該狀態機來遍歷並匹配輸入字串。
3.1.將 Stream API 與模式和謂詞結合使用
Java Stream API 提供了一種便捷的方法來過濾列表,我們可以將其與Pattern.compile()
類別結合起來應用正規表示式過濾:
List<String> filterUsingPatternAndPredicate() {
List<String> fruits = List.of("apple", "banana", "cherry", "apricot", "avocado");
Pattern pattern = Pattern.compile("^a.*");
return fruits.stream()
.filter(pattern.asPredicate()).toList();
}
過濾器選擇以“a”
開頭的字串,返回輸出: [apple, apricot, avocado]
。
3.2.使用String.matches()
方法
讓我們使用String.matches()
方法,它匹配整個字串並傳回true
,否則傳回false
:
List<String> filterUsingStringMatches() {
List<String> list = List.of("123", "abc", "456def", "789", "xyz");
return list.stream()
.filter(str -> str.matches("\\d+")).toList();
}
它會建立一個包含一位或多位數字的新清單。上述代碼的結果清單將是: [123, 789]
。
3.3.將Pattern.compile()
與迴圈結合使用
如果我們不想使用 Stream API(即 JDK 版本 <8),我們可以使用循環和Pattern.matcher()
方法:
List<String> filterUsingPatternCompile() {
List<String> numbers = List.of("one", "two", "three", "four", "five");
List<String> startWithTList = new ArrayList<>();
Pattern pattern = Pattern.compile("^t.*");
for (String item : numbers) {
Matcher matcher = pattern.matcher(item);
if (matcher.matches()) {
startWithTList.add(item);
}
}
return startWithTList;
}
上面的程式碼會建立一個新列表,其中包含以“t”
開頭的字串。預期結果將是: [two, three]
。
3.4.使用Collectors.partitioningBy()
進行條件分組
我們也可以使用 Stream API,透過Pattern.compile()
方法來過濾元素並有條件地建立兩個清單:
Map<Boolean, List<String>> filterUsingCollectorsPartitioningBy() {
List<String> fruits = List.of("apple", "banana", "apricot", "berry");
Pattern pattern = Pattern.compile("^a.*");
return fruits.stream()
.collect(Collectors.partitioningBy(pattern.asPredicate()));
}
這段程式碼再次過濾了以“a”
開頭的元素,預期結果是:Matches(key=true): [apple, apricot]
Non-Matches(key=false): [banana, berry]
4. 結論
在本文中,我們了解了使用正規表示式過濾清單的幾種技術。在我們看到的幾個選項中,使用 Stream API 因其可讀性和簡潔的語法而脫穎而出。
此外,將其與Pattern
和Predicate
結合被證明是非常有效率的,特別是在處理較大的資料集時。這是因為該Pattern
僅編譯一次,然後重複使用,從而節省了處理時間。
此外,Stream API 的效能非常好,使我們能夠無縫連結多個操作。當然,根據您情況的具體要求,可以採用其他方法,但 Stream API 往往會在清晰度和效能之間取得完美的平衡。
與往常一樣,本文的源代碼可在 GitHub 上取得。