Swift5中如何按自定义CharacterSet规则排序含特殊Unicode字符的字符串
Swift 5 含特殊Unicode字符的非英文字符串自定义排序方案
Swift 5 原生支持这类自定义排序,无需引入第三方依赖,结合你已经生成好目标字典序CharacterSet序列的前提,可直接选用以下两种实现:
方案1:基于字符权重映射的轻量实现(适配自定义CharacterSet规则)
先将按序排列的CharacterSet序列转换为「Unicode标量-排序优先级」的映射表,比对字符串时逐位取字符查询优先级判断顺序即可,性能足以覆盖绝大多数业务场景:
// 传入参数:待排序字符串数组、已按目标字典序排好的CharacterSet数组 func customSort(originArray: [String], orderedCharSets: [CharacterSet]) -> [String] { // 生成字符优先级映射 var charPriority: [Unicode.Scalar: Int] = [:] for (priority, charSet) in orderedCharSets.enumerated() { for scalar in charSet { charPriority[scalar] = priority } } // 自定义比对逻辑 return originArray.sorted { lhs, rhs in let lhsScalars = Array(lhs.unicodeScalars) let rhsScalars = Array(rhs.unicodeScalars) let compareCount = min(lhsScalars.count, rhsScalars.count) for i in 0..<compareCount { // 未纳入自定义规则的字符统一分配最高优先级值,排到列表末尾 let lP = charPriority[lhsScalars[i], default: Int.max] let rP = charPriority[rhsScalars[i], default: Int.max] guard lP == rP else { return lP < rP } // 同优先级字符按Unicode值兜底排序,避免同字符集内顺序混乱 guard lhsScalars[i] == rhsScalars[i] else { return lhsScalars[i] < rhsScalars[i] } } // 前缀完全相同时,更短的字符串排在前面 return lhsScalars.count < rhsScalars.count } }
如果排序规则需要区分大小写、重音字符变体,直接在生成CharacterSet时将对应字符拆分到不同优先级的集合中即可,无需额外做字符串预处理。
方案2:系统原生多语言排序适配(匹配官方地区字典序场景)
如果你的目标字典序和某一地区的官方语言排序规则一致,不需要手动维护CharacterSet序列,直接调用系统字符串比对接口即可,对组合重音字符、特殊Unicode符号、生僻字的兼容性更稳定:
// 示例:按加拿大法语字典序排序,区分大小写、忽略重音差异 let sortedArray = targetArray.sorted { $0.compare($1, options: [.diacriticInsensitive], locale: Locale(identifier: "fr_CA")) == .orderedAscending }
你数年前见过的旧版排序便捷方法(比如Swift 2/3时代的
localizedCaseInsensitiveCompare)并未被移除,只是相关能力都整合进了compare(_:options:range:locale:)方法,通过参数组合可以覆盖所有旧方法的功能。
注意事项
- 不要直接用
<运算符对非英文、含特殊Unicode的字符串做排序,该运算符默认按Unicode标量值排序,和通用语言字典序的排序结果差异极大 - 处理含emoji、零宽字符、组合重音标记的字符串时,优先遍历
unicodeScalars做比对,或先用folding(options:locale:)做归一化处理,避免把组合标记拆分为独立字符导致排序异常
内容的提问来源于stack exchange,提问作者BlueskyMed
相关产品推荐
相关产品推荐

