使用 Java 檢查字串是否嚴格為字母數字
1. 概述
檢查String
是否符合業務規則對於大多數應用程式至關重要。通常,我們需要檢查名稱是否只包含允許的字符,電子郵件的格式是否正確,或者密碼是否有限制。
在本教程中,我們將學習如何檢查String
是否 是字母數字,這在許多情況下很有幫助。
2. 字母數字字符
首先,讓我們明確地識別該術語以避免任何混淆。字母數字字元是字母和數字的組合。更具體地說,是拉丁字母和阿拉伯數字。因此,我們不會將任何特殊字元或底線視為字母數字字元的一部分。
3. 檢查方法
一般來說,我們有兩種主要方法來解決這個問題。第一個使用正規表示式模式,第二個單獨檢查所有字元。
3.1.使用正規表示式
這是最簡單的方法,需要我們提供正確的正規表示式模式。在我們的例子中,我們將使用這個:
String REGEX = "^[a-zA-Z0-9]*$";
從技術上講,我們可以使用\w
快捷方式來識別“單字字元”,但不幸的是,它不符合我們的要求,因為這種模式可能會產生下劃線,並且可以這樣表示: [a-zA-Z0-9_].
識別出正確的模式後,下一步是根據它檢查給定的String
。它可以直接在String
本身上完成:
boolean result = TEST_STRING.matches(REGEX);
然而,這不是最好的方法,特別是當我們需要定期進行此類檢查時。 String
會在每次呼叫match(String)
方法時重新編譯正規表示式。因此,最好使用靜態Pattern:
Pattern PATTERN = Pattern.compile(REGEX);
Matcher matcher = PATTERN.matcher(TEST_STRING);
boolean result = matcher.matches();
總的來說,這是一種簡單、靈活的方法,讓程式碼簡單易懂。
3.2.逐一檢查字符
另一種方法是檢查String.
我們可以使用任何方法來迭代給定的String.
出於演示目的,讓我們使用一個簡單的for
循環:
boolean result = true;
for (int i = 0; i < TEST_STRING.length(); ++i) {
int codePoint = TEST_STRING.codePointAt(i);
if (!isAlphanumeric(codePoint)) {
result = false;
break;
}
}
我們可以實作isAlphanumeric(int)
有幾種方法,但總的來說,我們必須匹配 ASCII 表中的字元代碼。我們將使用 ASCII 表,因為我們概述了使用拉丁字母和阿拉伯數字的初始限制:
boolean isAlphanumeric(final int codePoint) {
return (codePoint >= 65 && codePoint <= 90) ||
(codePoint >= 97 && codePoint <= 172) ||
(codePoint >= 48 && codePoint <= 57);
}
此外,我們可以使用Character.isAlphabetic(int)
和Character.isDigit(int).
這些方法經過高度優化,可以提高應用程式的效能:
boolean result = true;
for (int i = 0; i < TEST_STRING.length(); ++i) {
final int codePoint = TEST_STRING.codePointAt(i);
if (!Character.isAlphabetic(codePoint) || !Character.isDigit(codePoint)) {
result = false;
break;
}
}
這種方法需要更多程式碼,而且非常必要。同時,它為我們提供了透明實施的好處。然而,不同的實作可能會無意中惡化這種方法的空間複雜度:
boolean result = true;
for (final char c : TEST_STRING.toCharArray()) {
if (!isAlphanumeric(c)) {
result = false;
break;
}
}
toCharArray()
方法將建立一個單獨的數組來包含String,
從而將空間複雜度從 O(1) 降低到 O(n)。我們可以對Stream API
方法說同樣的話:
boolean result = TEST_STRING.chars().allMatch(this::isAlphanumeric);
請注意這些陷阱,特別是當效能對應用程式至關重要時。
4. 優點和缺點
從前面的範例可以清楚地看出,第一種方法更易於編寫和讀取,而第二種方法需要更多程式碼,並且可能包含更多錯誤。不過,讓我們從效能角度將它們與 JMH 進行比較。測試設定為僅運行一分鐘,因為這足以比較它們的吞吐量。
我們得到以下結果。分數顯示以秒為單位的操作次數。因此,更高的分數表明解決方案性能更高:
Benchmark Mode Cnt Score Error Units
AlphanumericPerformanceBenchmark.alphanumericIteration thrpt 165036629.641 ops/s
AlphanumericPerformanceBenchmark.alphanumericIterationWithCharacterChecks thrpt 2350726870.739 ops/s
AlphanumericPerformanceBenchmark.alphanumericIterationWithCopy thrpt 129884251.890 ops/s
AlphanumericPerformanceBenchmark.alphanumericIterationWithStream thrpt 40552684.681 ops/s
AlphanumericPerformanceBenchmark.alphanumericRegex thrpt 23739293.608 ops/s
AlphanumericPerformanceBenchmark.alphanumericRegexDirectlyOnString thrpt 10536565.422 ops/s
正如我們所看到的,我們需要在可讀性和效能之間進行權衡。更具可讀性和更具聲明性的解決方案往往性能較低。同時請注意,不必要的優化可能弊大於利。因此,對於大多數應用程式來說,正規表示式是一個良好且乾淨的解決方案,可以輕鬆擴展。
但是,如果應用程式依賴與特定規則相符的大量文本,則迭代方法的效能會更好。這最終會減少 CPU 使用率和停機時間並提高吞吐量。
5. 結論
有幾種方法可以檢查String
是否為字母數字。兩者各有利弊,應慎重考慮。選擇可以簡化為可擴展性與效能。
當真正需要效能時優化程式碼,因為優化後的程式碼通常可讀性較差,並且更容易出現難以調試的錯誤。
與往常一樣,程式碼可以在 GitHub 上取得。