We may start by implementing a Swift 3 version of the chunk(n:)
method (for Collection
's) of oisdk:s SwiftSequence:
/* Swift 3 version of Github use oisdk:s SwiftSequence's 'chunk' method:
https://github.com/oisdk/SwiftSequence/blob/master/Sources/ChunkWindowSplit.swift */
extension Collection {
public func chunk(n: IndexDistance) -> [SubSequence] {
var res: [SubSequence] = []
var i = startIndex
var j: Index
while i != endIndex {
j = index(i, offsetBy: n, limitedBy: endIndex) ?? endIndex
res.append(self[i..<j])
i = j
}
return res
}
}
In which case implementing your custom formatting is a simple case of creating 4-character chunks and joining these by "-":
func customStringFormatting(of str: String) -> String {
return str.characters.chunk(n: 4)
.map{ String($0) }.joined(separator: "-")
}
Example usage:
print(customStringFormatting(of: "5022222222222222")) // 5022-2222-2222-2222
print(customStringFormatting(of: "50222222222222")) // 5022-2222-2222-22
print(customStringFormatting(of: "5022222")) // 5022-222
If applying to be used in the textField(_:shouldChangeCharactersIn:replacementString:)
method of UITextFieldDelegate
, we might want to filter out existing separators in the customStringFormatting(of:)
method method, as well as implementing it as a String
extension:
extension String {
func chunkFormatted(withChunkSize chunkSize: Int = 4,
withSeparator separator: Character = "-") -> String {
return characters.filter { $0 != separator }.chunk(n: chunkSize)
.map{ String($0) }.joined(separator: String(separator))
}
}
And implement the controlled updating of the textfield e.g. as follows:
let maxNumberOfCharacters = 16
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// only allow numerical characters
guard string.characters.flatMap({ Int(String($0)) }).count ==
string.characters.count else { return false }
let text = textField.text ?? ""
if string.characters.count == 0 {
textField.text = String(text.characters.dropLast()).chunkFormatted()
}
else {
let newText = String((text + string).characters
.filter({ $0 != "-" }).prefix(maxNumberOfCharacters))
textField.text = newText.chunkFormatted()
}
return false
}
The last part above will truncate possible pasted strings from the user (given that it's all numeric), e.g.
// current
1234-1234-123
// user paste:
777777777
/* ^^^^ will not be included due to truncation */
// will result in
1234-1234-1237-7777
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…