How to masking the last number in Swift?
Use a prefix instead of a suffix
extension StringProtocol {
var masked: String {
return prefix(5) + String(repeating: "•", count: Swift.max(0, count-5))
}
}
You could also create a function instead for parameterizing the number of digits and direction (or even the mask character)
extension StringProtocol {
func masked(_ n: Int = 5, reversed: Bool = false) -> String {
let mask = String(repeating: "•", count: Swift.max(0, count-n))
return reversed ? mask + suffix(n) : prefix(n) + mask
}
}
var name = "0123456789"
print(name.masked(5))
// 01234•••••
print(name.masked(5, reversed: true))
// •••••56789
Card Number Masking
Your question contains 2 important parts:
A regex that matches all characters but first 6 and last 2
let regexPattern = "(?<=.{6}).(?=.*.{2}$)"
and
An extension on the String
that takes the regex and masks it:
extension String {
func masked(matching regexPattern: String, with template: String = "*") throws -> String {
let regex = try NSRegularExpression(pattern: regexPattern, options: NSRegularExpression.Options.caseInsensitive)
let range = NSMakeRange(0, count)
return regex.stringByReplacingMatches(in: self, options: [], range: range, withTemplate: template)
}
}
Usage:
let cardNumber = "5890040000000016"
let regexPattern = "(?<=.{6}).(?=.*.{2}$)"
print("Output:", try! cardNumber.masked(matching: regexPattern))
Output: 589004********16
How to mask a String to show only the last 3 characters?
This does exactly what you want:
let name = "0123456789"
let conditionIndex = name.characters.count - 3
let maskedName = String(name.characters.enumerated().map { (index, element) -> Character in
return index < conditionIndex ? "x" : element
})
print("Masked Name: ", maskedName) // xxxxxxx789
What happens here is that you get an array of the characters of the string using enumerated()
method, then map each character to a value based on a condition:
- If the index of the character is less than
condtionIndex
we replace the character with anx
(the mask). - Else, we just leave the character as is.
How to masking textfield in Swift 4?
func hide(email: String) -> String {
let parts = email.split(separator: "@")
if parts.count < 2 {
return email
}
let name = parts[0]
let appendix = parts[1]
let lenght = name.count
if lenght == 1 {
return "*@\(appendix)"
}
let semiLenght = lenght / 2
var suffixSemiLenght = semiLenght
if (lenght % 2 == 1) {
suffixSemiLenght += 1
}
let prefix = String(repeating: "*", count: semiLenght)
let lastPart = String(name.suffix(suffixSemiLenght))
let result = "\(prefix)\(lastPart)@\(appendix)"
return result
}
let email = "123456789@gmail.com"
let result = hide(email: email)
print(result)
Masking email and phone number in Swift 4
Basically, you could use a function like this. It hides all chars despite the leading and trailing two chars:
func hideMidChars(_ value: String) -> String {
return String(value.enumerated().map { index, char in
return [0, 1, value.count - 1, value.count - 2].contains(index) ? char : "*"
})
}
Please note there's currently no special handling done for very short input strings.
Using this function for the phone number should be trivial; as for the email, if you only want to hide the first part, you could use the following code:
let email = "123456@test.com"
let components = email.components(separatedBy: "@")
let result = hideMidChars(components.first!) + "@" + components.last!
The result
constant will be 12**56@test.com
.
This of course assumes that the email is in a valid format, otherwise force unwrapping the first and last array component could crash. However, handling this would be out of scope for this question.
How can i mask the first and last characters in Swift?
Pretty simple, really. You just need to reverse the order of the characters from the string and the mask in the "not lastCharacters" case:
extension String {
func maskedChar(_ charCount: Int, lastCharacters: Bool = true) -> String {
if self.count < charCount {
return String(repeating: "*", count: self.count)
}
let mask = String(repeating: "*", count: charCount)
if lastCharacters {
return self.prefix(self.count - charCount) + mask
} else {
return mask + self.suffix(self.count - charCount)
}
}
}
Note that I also changed the if clause at the beginning. It seems to me you should ALWAYS mask the data, even if the source string is too short.
Masking First and Last Name String with *
You could e.g. use pattern matching for lower-case characters and replace those that match the pattern with asterisk characters (*
):
let name = "Johnny Tuck"
let pattern = Character("a")..."z"
let maskedName = String(name.characters.map { pattern ~= $0 ? Character("*") : $0 })
print(maskedName) // J***** T***
If the purpose is not to replace lower case characters by *
but rather to mask all characters that are not the first of a given word (for, say, a specific separator " "
), you could separate the String
name by a separator, and apply a masking to all but the initial character for all separated words (sub-names), follwed by finally reconstruct the masked string:
import Foundation
let name = "johnny lucky tuck"
let maskedName = name.components(separatedBy: " ")
.filter { !$0.isEmpty }.map { $0.characters }
.map { String($0.first!).uppercased() + String(repeating: "*", count: $0.dropFirst(1).count) }
.joined(separator: " ")
print(maskedName) // J***** L**** T***
Note the uppercased()
above, which sets the initial non-masked letter to a uppercased one (even if it is not initially). If you do not wish this uppercasing, simply remove the .uppercased()
call above.
Masking characters in a Swift string
Use replacingOccurrences
with options:
let str = "abcdba"
let result = str.replacingOccurrences(of: "[^ab]", with: "", options: .regularExpression)
print(result) //"abba"
Or you could define a function like this:
func maskString (
_ str: String,
withMask mask: String ,
replaceWith replacement: String = ""
) -> String {
return str
.replacingOccurrences(of: "[^\(mask)]",
with: replacement,
options: .regularExpression)
}
And use it like so:
maskString("abcdba", withMask: "ab") //"abba"
maskString("abcdba", withMask: "ab" , replaceWith: "?") //"ab??ba"
Mask textField in swift
This way you can create a telephone mask in Swift.
First create a nifty extension for the String type. The subscript gets the character at an index and the function gets a String.Index type from an int!.
extension String {
subscript (i: Int) -> String {
if countElements(self) > i {
return String(Array(self)[i])
}
return ""
}
func indexAt(theInt:Int)->String.Index {
return advance(self.startIndex, theInt)
}
}
And this is the function to call on the text in your phone number entry field:
func returnMaskedPhoneField(thePhoneText:String)->String{
var returnString = thePhoneText
//Trims non-numerical characters
returnString = returnString.stringByTrimmingCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet)
//Removes all spaces
returnString = returnString.stringByReplacingOccurrencesOfString(" ", withString: "")
//Checks if we need to format a mobile number
if thePhoneText[1] == "4"{
if countElements(returnString) > 7 {
returnString = returnString.stringByReplacingCharactersInRange(Range<String.Index>(start: returnString.indexAt(7), end: returnString.indexAt(7)), withString: " ")
}
if countElements(returnString) > 4 {
returnString = returnString.stringByReplacingCharactersInRange(Range<String.Index>(start: returnString.indexAt(4), end: returnString.indexAt(4)), withString: " ")
}
}else {
if countElements(returnString) > 6 {
returnString = returnString.stringByReplacingCharactersInRange(Range<String.Index>(start: returnString.indexAt(6), end: returnString.indexAt(6)), withString: " ")
}
if countElements(returnString) > 2 {
returnString = returnString.stringByReplacingCharactersInRange(Range<String.Index>(start: returnString.indexAt(2), end: returnString.indexAt(2)), withString: " ")
}
}
return returnString
}
Then then here is where you would implement the function, put this in your viewDidLoad
method:
aTextField.delegate = self
aTextField.addTarget(self, action: "validateTextFields:", forControlEvents: UIControlEvents.EditingChanged)
And this one somewhere in the class that's your textfield
delegate:
func validateTextFields(sender:AnyObject){
if let textField = sender as? UITextField {
if textField == aTextField {
if let currentCurserPosition = aTextField?.selectedTextRange {
var isEndOfString = false
let currentCurserPositionInteger = textField.offsetFromPosition(textField.beginningOfDocument, toPosition: currentCurserPosition.start)
if currentCurserPositionInteger == count(textField.text){
isEndOfString = true
}
aTextField?.text = returnMaskedPhoneField(textField.text)
if isEndOfString == false {
aTextField?.selectedTextRange = currentCurserPosition
}
}else {
aTextField?.text = returnMaskedPhoneField(textField.text)
}
}
}
}
And it will work like:
Credits:
http://pjeremymalouf.com/creating-a-text-mask-in-swift/
And if you want to use custom textField
then you can use AKMaskField.
Where you can find textField
for phone like this:
Related Topics
Images Inaccessible from Asset Catalog in a Swiftui Framework
Nstableview Get Indexpath Having the Cell
Deep Copy of Cmimagebuffer or Cvimagebuffer
Drag a Cgrect Using Uipangesturerecognizer
MAC App to Switch Between /Etc/Hosts Files, How to Allow Access
Set Insets to the Collectionview Programmatically in Swift
Swiftui [Bug] Navigationview and List Not Showing on iPad Simulator Only
Overloads for '...' Exist with These Result Types: Closedrange<Bound>, Countableclosedrange<Bound>
Comparing Two Enum Variables Regardless of Their Associated Values
Swiftui: How to Set Position of Scrollview to Top Left? (Both Scrolls Is Enabled)
Get the First Day of Week Without Weekcalendarunit
Swift - Writing a Byte Stream to File
Coerced to Any' But Property Is of Type Uicolor
Instance Member Cannot Be Used on Type | Closures
Self' Is Only Available in a Protocol or as the Result of a Class Method