有多个线程讨论如何复制 NSString 的
boolValue
方法,但大多数都是猜测或简化。
Apple 只给了我们这个简短的描述:
遇到“Y”、“y”、“T”、“t”或数字 1-9 之一时,此属性为 YES — 该方法忽略任何尾随字符。如果接收者不以数字的有效十进制文本表示形式开始,则此属性为“否”。 该属性采用十进制表示形式并跳过字符串开头的空格。它还会跳过初始空白字符或可选的 -/+ 符号后跟零。
那么它认为什么是空白呢? “采用十进制表示”是什么意思?
我正在转换现有的 Objective-C 应用程序并将其转换为 Swift,并且想要一个真正的 Swift
boolValue
方法,而无需先将字符串转换为 NSString(即 (string as NSString).boolValue()
)
事实证明,Apple 的简洁描述是完整且正确的!空白是 null、空格和制表符的集合。 “0”的运行可以选择添加“+”或“-”前缀。
这个 Swift 代码完全复制了 NSString 函数(至少对于 ASCII 来说
extension String {
var boolValue: Bool {
guard !self.isEmpty else { return false }
// NSString treats these as "false" "\u{000A}", "\u{000B}", "\u{000C}", "\u{000D}",
let whiteSpace: Set<Character> = ["\u{0000}", "\u{0009}", "\u{0020}" ]
let trueChar: Set<Character> = ["t", "T", "y", "Y", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
let trueNum: Set<Character> = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]
let zeroRun: Set<Character> = ["+", "-", "0"]
var index = self.startIndex
let lastIndex = self.endIndex
var c: Character
repeat {
c = self[index]
index = self.index(index, offsetBy: 1)
} while whiteSpace.contains(c) && index < lastIndex; // up to the last character
if zeroRun.contains(c) && index < lastIndex {
repeat {
c = self[index]
index = self.index(index, offsetBy: 1)
} while c == "0" && index < lastIndex; // up to the last character
return trueNum.contains(c)
} else {
return trueChar.contains(c)
}
}
}
我可以声称兼容性的原因是,我创建了一个测试工具来将上述代码与 NSString
boolValue
方法进行比较,并确保两者使用以下代码为 1,000,000,000 个“模糊”测试返回相同的值:
func test() {
func random() -> String {
let val = Int.random(in: 0..<128)
let c = String(format: "%c", val)
return c
}
var i = 0
while true {
var s = ""
let len = Int.random(in: 1..<16)
for _ in 0..<len {
s += random()
}
let oTest = (s as NSString).boolValue
let sTest = s.boolValue
if oTest != sTest {
print("Testing \(s) oTest=\(oTest) sTest=\(sTest)")
for c in s {
print("HEX:", String(format: "%2.2X char=%c", c.asciiValue!), c)
}
var str = "\""
for c in s {
str += String(format: "\\u{%4.4X}", c.asciiValue!)
}
str += "\""
print(str)
fatalError()
}
i += 1
if i % 1_000_000 == 0 {
print("Count \(i)")
if i == 1_000_000_000 {
break
} else {
sleep(1)
}
}
}
}
请注意,字符串包含 ASCII 0 到 127 范围内的随机字符。
当然,我的编码失败了好几次才得到正确的结果!