swift - 电话号码的自定义 Swift 格式化程序
问题描述
我需要一个简单的 Swift 电话号码格式化程序来添加到 NSTextField。
我很难理解文档和示例,特别是对于 getObjectValue(_:, for:, errorDescription) -> Bool 函数的 obj?.pointee 用法。AutoreleasingUnsafeMutablePointer 的概念?从文档中看很难,我在网上找不到太多关于自定义 Swift 格式化程序的信息。我查看了 Marmel Roy 的 PhoneNumberKit,但它似乎对我的需求来说太复杂了,并且没有描述如何直接添加到格式化程序。
override func getObjectValue(_ obj: AutoreleasingUnsafeMutablePointer<AnyObject?>?, for string: String, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
obj?.pointee = someConversionToInternalString(typedString)
return true
}
上述失败,重复只是存储一个空字符串。
解决方案
经过一些工作,我想出了如何做到这一点。我希望它会节省其他人这样做的时间。我的解决方案的关键是将“对象”存储为 Cocoa 对象(即目标 C 类型);这里作为 NSString 而不是 String。这是一些完整的示例代码,可以对满足我的条件的电话号码进行(简单)格式化。
import Foundation
class PhoneFormatter: Formatter {
override init() {
super.init()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
func reduceToPhoneCharacters(string: String) -> String {
let plusSign = string.prefix(1) == "+"
// remove any non-digit characters
let str = string.digits
return "\(plusSign ? "+" : "")\(str)"
}
func displayString(string: String) -> String? {
// take a string of symbols and convert into a formatted phone number (US, Aust, Europe)
if string.isBlank || !string.isPhoneCharacters { return string } // will see if it improves
let plusSign = string.prefix(1) == "+"
// remove any non-digit characters
let str = string.digits
// international, + at start, recognise only US, Australian, NZ or European
if plusSign {
// USA
if str.prefix(1) == "1" {
return "+" + str.substring(start: 0, length: 1) + " (" + str.substring(start: 1, length: 3) + ") " + str.substring(start: 4, length: 3) + "-" + str.substring(start: 7, length: 4)
}
// Australia
if str.prefix(2) == "61" || str.prefix(2) == "64" {
return "+" + str.substring(start: 0, length: 3) + "-" + str.substring(start: 3, length: 4) + "-" + str.substring(start: 7, length: 4)
}
// Others? eg +44-123-456789
return "+" + str.substring(start: 0, length: 2) + "-" + str.substring(start: 3, length: 4) + "-" + str.substring(start: 7, length: 10)
}
// mobile if begins with 04
if str.prefix(2) == "04" {
return str.substring(start: 0, length: 4) + "-" + str.substring(start: 4, length: 3) + "-" + str.substring(start: 7, length: 3)
}
// interstate
if str.prefix(1) == "0" {
return str.substring(start: 0, length: 2) + "-" + str.substring(start: 2, length: 4) + "-" + str.substring(start: 6, length: 4)
}
// 1800 or 1300 numbers
if str.prefix(4) == "1800" || str.prefix(4) == "1300" {
return str.substring(start: 0, length: 1) + "-" + str.substring(start: 1, length: 3) + "-" + str.substring(start: 4, length: 3) + "-" + str.substring(start: 7, length: 4)
}
// else Victoria substring
return str.substring(start: 0, length: 4) + "-" + str.substring(start: 4, length: 4)
}
override func string(for obj: Any?) -> String? {
// take a string of symbols and convert into a formatted phone number (US, Aust, Europe)
guard let str = obj as? NSString else { return nil }
return displayString(string: str as String)
}
override func getObjectValue(_ obj: AutoreleasingUnsafeMutablePointer<AnyObject?>?, for string: String, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
obj?.pointee = reduceToPhoneCharacters(string: string) as NSString
return true
}
override func editingString(for obj: Any) -> String? {
if let str = obj as? NSString {
return str as String
}
return nil
}
override func isPartialStringValid(_ partialString: String, newEditingString newString: AutoreleasingUnsafeMutablePointer<NSString?>?, errorDescription error: AutoreleasingUnsafeMutablePointer<NSString?>?) -> Bool {
return partialString.isPhoneCharacters || partialString == ""
}
}
// separate +String.swift file for extensions
import Foundation
extension String {}
var digits: String {
return components(separatedBy: CharacterSet.decimalDigits.inverted).joined()
}
var isPhoneCharacters: Bool {
return !isEmpty && range(of: "[^+\\d]", options: .regularExpression) == nil
}
func substring(start: Int, length : Int) -> String {
if (count > start + length) {
let startAtIndex = index(startIndex, offsetBy: start)
return String(self[startAtIndex...index(startAtIndex, offsetBy: length - 1)])
}
if count > start {
let startAtIndex = index(startIndex, offsetBy: start)
return String(self[startAtIndex...])
}
return ""
}
}
并以编程方式使用它,例如:
@IBOutlet weak var phoneTextField: NSTextField!
phoneTextField.formatter = PhoneFormatter()
我对此进行了编辑以删除冗余代码并使用 editingString(for:) 函数。
推荐阅读
- java - 为什么不收集我的内容解析器的所有歌曲/文件?
- c - 如何读取多行的字符串并打印偶数位字符和奇数位字符,每个stri中用空格分隔
- asp.net-mvc - 如何将 IStringLocalizer 注入 IApplicationModelConvention?
- mongodb - MongoDb 文本搜索返回空结果
- c# - DelegatingHandler 在返回 Task 时挂起
- python - 对每一行中的单词进行排序
- neo4j - 无法通过浏览器连接到 neo4j,neo4j 浏览器中的螺栓端口已更改
- android - 来自 Qt Android C++ Firebase 的哄骗日志信息(通知不起作用)
- amazon-web-services - 从 AWS CloudFront 中删除 Cache-Control 标头?
- c++ - 打印此矩阵的 if 语句是什么