2024年4月1日 星期一

Swift 字串遮罩

 這邊直接提供一個共用只要是字串都可已的方法

struct SecureText {

    private var originalText: String

    var prefixRange: Int!

    var numberOfStars: Int!

    

    init(_ text: String, prefix: Int, numberOfStars: Int) {

        self.originalText = text

        self.prefixRange = prefix

        self.numberOfStars = numberOfStars

    }

    

    var secureText: String {

        let firstRange = originalText.prefix(prefixRange)

        let endRange = originalText.suffix(originalText.count - prefixRange - numberOfStars)

        return String(firstRange) + String(repeating: "*", count: numberOfStars) + String(endRange)

    }

    

    var text: String {

        return originalText

    }

}

ex: 

let securePhone = SecureText("0987654987", prefix: 2, numberOfStars: 4)

print(securePhone.secureText) //輸出結果 "09****4987"

print(securePhone.text)   //輸出結果 "0987654987"

簡單說明一下,prefix為要遮罩的第幾位字元,numberOfStars為要遮罩幾字元。

假設您有特殊需求譬如遇到某個字但不知道整串字串為幾個字元時,就是計算該字在第幾字元,並且定義一個顯示標準去決定從第幾字元開始遮罩並遮罩幾字元。

但是除了上述的方法外可以按照個別需求去做單一邏輯的做法,例如:姓名、信箱、手機、地址等。

上述的四種我都會提供範例於下方,這邊就不多做輸出結果只提供使用範例...

以下的寫法我都是寫在String extension裡面,你可以自己再進行調整

姓名遮罩,邏輯是兩個字以下遮前,三個字以上只顯示頭尾

func markName() -> String {

        var nameToMask = self

        var isKids = false

        var maskedName = ""

        

        if nameToMask.count < 3 { // 姓名為兩個字的情況

            let lastChar = "*" + String(nameToMask.suffix(1))

            maskedName = lastChar

        } else {  // 姓名為三個字以上的情況

            let firstChar = String(nameToMask.prefix(1))

            let lastChar = String(nameToMask.suffix(1))

            let middleMask = String(repeating: "*", count: nameToMask.count - 2)

            

            maskedName = firstChar + middleMask + lastChar

        }

        

        return maskedName

    }

信箱遮罩,邏輯是取出帳號,並且帳號如果小於四字元顯示最後一字元,大於的話則顯示最後三字元

 func markEmail() -> String {

        guard self != "", self.contains("@") else {

            return ""

        }

        let mails = self.components(separatedBy: "@")

        let acount = mails[0]

        let mailHost = mails[1]

        var maskMail = ""

        

        if acount.count <= 4 {

            maskMail = String(repeating: "*", count: acount.count - 1) + String(acount.suffix(1)) + "@" + mailHost

        } else {

            let suffix = String(acount.suffix(3))

            maskMail = String(repeating: "*", count: acount.count - 3) + suffix + "@" + mailHost

        }

        return maskMail

    }

手機遮罩,顯示前四碼及最後兩碼

func maskPhone() -> String {

        guard self != "" else {

            return ""

        }

        let first = String(self.prefix(4))

        let last = String(self.suffix(2))

        let maskPhone = String(repeating: "*", count: self.count - 6)

        return first + maskPhone + last

    }

地址遮罩,這邊做法是判斷阿拉伯數字(因應大家習慣基本門牌號碼或是巷弄之類皆款性輸入啊拉博數字的撞太下),然後將數字前所有字串遮罩,你也可以改寫成顯示縣市地區至數字之間遮罩

func maskAddress() -> String {

        var maskedAddress = ""

        var foundDigit = false

        

        for (i, char) in self.enumerated() {

            let predicate = NSPredicate(format: "SELF MATCHES %@", "[0-9]")

            if predicate.evaluate(with: String(char)) && !foundDigit {

                foundDigit = true

                let index = self.count - i

                let suffix = String(self.suffix(index))

                maskedAddress = String(repeating: "*", count: i)

                maskedAddress = maskedAddress + suffix

                break

            }

        }

        return maskedAddress

    }


以上的方法全部都是類似規則,要注意的主要就是當您使用

String(repeating: <#T##String#>, count: <#T##Int#>)

後面count數基本上就是你要遮罩替換的字數,所以你會看到我直接帶字串的count - Int,

這寫法是你清楚有幾個字沒遮罩,向地址就是帶入i,因為我知道第i為數字,所以i以前都是要遮罩的。

使用方法就是字串直接點運算你要的方法例如"0988666888".maskPhone()

以上分享希望對於剛好有需求的朋友有所幫助