屏蔽除最後 N 個字元之外的字串
1. 概述
在 Java 中,我們經常需要屏蔽String
,例如隱藏日誌檔案中列印或顯示給使用者的敏感資訊。
在本教程中,我們將探討如何使用一些簡單的 Java 技術來完成此任務。
2.問題介紹
在許多情況下,我們可能需要封鎖敏感訊息,例如信用卡號、社會安全號,甚至電子郵件地址。執行此操作的常見方法是隱藏String
中除最後幾個字元之外的所有字元。
像往常一樣,範例有助於快速理解問題。假設我們有三個敏感的String
值:
static final String INPUT_1 = "abcd 1234";
static final String INPUT_2 = "abcd ";
static final String INPUT_3 = "ab";
現在,我們要屏蔽這些String
值中的所有字符 除了最後一個N
。為簡單起見,在本教程中,我們採用N=4
並使用星號 (*) 來屏蔽每個字元。因此,預期結果是:
static final String EXPECTED_1 = "********1234";
static final String EXPECTED_2 = "******** ";
static final String EXPECTED_3 = "ab";
正如我們所看到的,如果輸入String
的長度小於或等於N
(4),我們將跳過對其進行屏蔽。此外,我們將空白字元視為與常規字元相同。
接下來,我們將以這些String
輸入為例,並使用不同的方法對其進行屏蔽以獲得預期的結果。像往常一樣,我們將利用單元測試斷言來驗證每個解決方案是否正常運作。
3.使用char
數組
我們知道String
是由char
序列組成的。因此,我們可以將String
輸入轉換為char
數組,然後將屏蔽邏輯應用於char
數組:
String maskByCharArray(String input) {
if (input.length() <= 4) {
return input;
}
char[] chars = input.toCharArray();
Arrays.fill(chars, 0, chars.length - 4, '*');
return new String(chars);
}
接下來,讓我們逐步了解其實現並了解其工作原理。
首先,我們檢查輸入的長度是否小於或等於4
。如果是這樣,則不套用掩碼,並且我們按原樣返回輸入String
。
然後,我們使用toCharArray()
方法將輸入String
轉換為char[]
.
接下來,我們利用Arrays.fill()
來屏蔽字元。 Arrays.fill()
允許我們定義輸入char[]
的哪一部分需要用特定字元填入。在本例中,我們只想從陣列開頭fill()
chars.length – 4
字元。
最後,在屏蔽char
陣列的所需部分後,我們使用new String(chars)
將其轉換回String
並傳回結果。
接下來,讓我們測試一下這個解決方案是否如預期般運作:
assertEquals(EXPECTED_1, maskByCharArray(INPUT_1));
assertEquals(EXPECTED_2, maskByCharArray(INPUT_2));
assertEquals(EXPECTED_3, maskByCharArray(INPUT_3));
正如測試所示,它正確地屏蔽了我們的三個輸入。
4. 兩個子串
我們的要求是屏蔽給定String
中除最後四個字元之外的所有字元。換句話說,我們可以將輸入String
分成兩個子字串:一個要屏蔽的子字串 ( toMask
),和一個要保持純文字的最後四個字元的子字串 ( keepPlain
) 。
然後,我們可以簡單地將toMask
子字串中的所有字元替換為“*”,並將兩個子字串連接在一起以形成最終結果:
String maskBySubstring(String input) {
if (input.length() <= 4) {
return input;
}
String toMask = input.substring(0, input.length() - 4);
String keepPlain = input.substring(input.length() - 4);
return toMask.replaceAll(".", "*") + keepPlain;
}
如程式碼所示,與char
數組方法類似,我們首先處理輸入的length() <= 4.
然後我們使用substring()
方法來提取兩個子字串: toMask
和keepPlain
。
我們要求replaceAll()
透過替換任何字元“.”來屏蔽toMask
。和 ”*」。值得注意的是, “.”這裡的參數是匹配任何字元的正規表示式 (regex),而不是字面句點字元。
最後,我們將屏蔽部分與未屏蔽部分( keepPlain
)連接起來並傳回結果。
這個方法也通過了我們的測試:
assertEquals(EXPECTED_1, maskBySubstring(INPUT_1));
assertEquals(EXPECTED_2, maskBySubstring(INPUT_2));
assertEquals(EXPECTED_3, maskBySubstring(INPUT_3));
正如我們所看到的,這種方法是解決這個問題的簡潔明了的方法。
5. 使用正規表示式
在兩個子字串的解決方案中,我們使用了replaceAll()
。我們也提到該方法支援正規表示式。事實上,透過使用replaceAll()
和聰明的正規表示式,我們可以一步有效地解決這個屏蔽問題。
接下來,讓我們看看這是如何完成的:
String maskByRegex(String input) {
if (input.length() <= 4) {
return input;
}
return input.replaceAll(".(?=.{4})", "*");
}
在此範例中,除了input.length() <=4
情況處理之外,我們僅透過一次replaceAll()
呼叫來套用屏蔽邏輯。接下來,讓我們來了解正規表示式的魔力“ .(?=.{4})
”
這是一個前瞻性斷言。它確保只有後面緊跟著四個字元的字元才保持未屏蔽狀態。
簡而言之,正規表示式尋找後面跟著四個字元 (.{4}) 的任何字元 (.) 並將其替換為“*”。這確保了只有最後四個之前的字元被屏蔽。
如果我們用輸入進行測試,我們會得到預期的結果:
assertEquals(EXPECTED_1, maskByRegex(INPUT_1));
assertEquals(EXPECTED_2, maskByRegex(INPUT_2));
assertEquals(EXPECTED_3, maskByRegex(INPUT_3));
正規表示式方法可以在一次傳遞中有效地處理屏蔽,使其成為簡潔程式碼的理想選擇。
6. 使用repeat()
方法
從 Java 11 開始, repeat()
方法加入了String
家族。它允許我們透過多次重複某個字元來創建一個String
值。如果我們使用Java 11或更高版本,我們可以使用repeat()
來解決屏蔽問題:
String maskByRepeat(String input) {
if (input.length() <= 4) {
return input;
}
int maskLen = input.length() - 4;
return "*".repeat(maskLen) + input.substring(maskLen);
}
在此方法中,我們首先計算掩碼長度( maskLen
): input.length() -4
。然後,我們直接重複所需長度的掩碼字符,並將其與未遮罩的子字串連接起來,形成最終結果。
像往常一樣,讓我們使用輸入String
來測試這種方法:
assertEquals(EXPECTED_1, maskByRepeat(INPUT_1));
assertEquals(EXPECTED_2, maskByRepeat(INPUT_2));
assertEquals(EXPECTED_3, maskByRepeat(INPUT_3));
正如測試所示, repeat()
方法可以完成這項工作。
七、結論
在本文中,我們探索了屏蔽String
同時保持最後四個字元可見的不同方法。
值得注意的是,儘管我們在本教程中選擇了“*”字元來屏蔽敏感資訊並保持最後四個(N = 4)字元可見,但這些方法可以輕鬆調整以適應不同的要求,例如不同的屏蔽字元或N值。
與往常一樣,範例的完整原始程式碼可在 GitHub 上取得。