Swift中String扩展isValidEmail函数逻辑及inverted属性疑问
关于Swift CharacterSet.inverted的疑问解答
首先拆解你的问题,一步步来解释:
1. inverted的核心作用
CharacterSet.inverted是获取当前字符集的补集——简单说就是:原字符集包含哪些字符,inverted后的集合就包含所有不在原字符集里的Unicode字符。
结合你的代码来看,逻辑是这样的:
- 你定义的
characterset是允许的字符(大小写字母+数字) characterset.inverted就是所有不允许的字符(比如俄语字母ъ、中文、特殊符号等等)self.rangeOfCharacter(from: characterset.inverted)的作用是:检查当前字符串里是否存在任何一个不允许的字符- 如果返回非nil(找到不允许的字符),就返回false(格式无效)
- 如果返回nil(没有找到不允许的字符),就返回true(所有字符都在允许范围内)
这完全符合你想要的校验逻辑——只允许大小写字母和数字的字符串通过校验。
2. 移除inverted后结果不符合预期的原因
如果去掉inverted,代码变成self.rangeOfCharacter(from: characterset),这个方法的作用就变成了:检查字符串里是否存在属于允许集合的字符。
那你的两个测试用例就会变成:
"Login":全是允许的字符,所以rangeOfCharacter(from:)返回非nil,代码进入if分支返回false,不符合预期"Loginъ":里面有允许的字符(Login部分),所以同样返回非nil,进入if分支返回false,也不符合预期
这就完全搞反了你的校验逻辑,所以结果不对。
3. Playground打印结果的误解
你在Playground里打印characterset和characterset.inverted看起来一样,是因为CFCharacterSet的print输出非常简略,它只会显示原字符集里的具体字符,不会把补集里的所有字符都列出来(毕竟补集包含几百万个Unicode字符,根本列不完)。
你可以在Playground里跑这段代码验证差异:
let charSet = CharacterSet(charactersIn: "a") let strA = "a" let strB = "b" // 检查是否存在属于charSet的字符 print(strA.rangeOfCharacter(from: charSet) != nil) // 输出true(找到'a') print(strB.rangeOfCharacter(from: charSet) != nil) // 输出false(找不到'a') // 检查是否存在属于charSet补集的字符(也就是除了'a'之外的所有字符) print(strA.rangeOfCharacter(from: charSet.inverted) != nil) // 输出false(没有非'a'的字符) print(strB.rangeOfCharacter(from: charSet.inverted) != nil) // 输出true('b'属于补集)
从这个测试就能明显看出,charSet和charSet.inverted是完全相反的两个集合,只是打印描述让你产生了误解。
内容的提问来源于stack exchange,提问作者Evgeniy Kleban
相关产品推荐
相关产品推荐

