Swift substring range函数在泰米尔语特定场景下匹配失败求助
泰米尔语带Pulli(U+0BCD)修饰符的子串精准匹配解决方案
问题重现
在Swift中使用range(of:)查找以泰米尔语Pulli(U+0BCD,纯辅音修饰符)结尾的子串时存在异常:子串位于字符串末尾时可正常匹配,位于中间时则匹配失败。示例代码及输出如下:
var s = "அவர்கள்" var ss1 = "அவர்" var ss2 = "கள்" if let r2 = s.range(of: ss2)?.lowerBound { print("INFO: Success! Found the substring",s[r2...],"in string",s) } else { print("ERROR: substring",ss2,"not found in string",s) } if let r1 = s.range(of: ss1)?.upperBound { print(s[..<r1]) } else { print("ERROR: substring",ss1,"not found in string",s) } print(s.unicodeScalars.map { $0 }) print(ss1.unicodeScalars.map { $0 }) print(ss2.unicodeScalars.map { $0 })
输出:
INFO: Success! Found the substring கள் in string அவர்கள் ERROR: substring அவர் not found in string அவர்கள் ["\u{0B85}", "\u{0BB5}", "\u{0BB0}", "\u{0BCD}", "\u{0B95}", "\u{0BB3}", "\u{0BCD}"] ["\u{0B85}", "\u{0BB5}", "\u{0BB0}", "\u{0BCD}"] ["\u{0B95}", "\u{0BB3}", "\u{0BCD}"]
泰米尔语的Pulli修饰符用于将带元音的辅音转为纯辅音,例如基础字符ர(U+0BB0)添加Pulli后变为ர்(U+0BB0 + U+0BCD)。此前有方案将Pulli视为变音符号忽略,但会导致非预期匹配:
- 预期:
s = "அவர்கள்", ss1 = "அவர்"→ 匹配成功 - 非预期:
s = "அவரகள்", ss1 = "அவர்"→ 匹配到அவர(无Pulli) - 非预期:
s = "அவராகள்", ss1 = "அவர்"→ 匹配到அவரா(带长元音修饰符)
问题分析
Swift默认的range(of:)使用语言感知的字符串匹配策略,会将某些Unicode字符组合视为语义等价(例如将变音符号与基础字符的组合做模糊匹配),导致无法精准匹配带Pulli的子串。同时,当子串位于字符串中间时,后续字符的存在可能干扰默认匹配逻辑,而末尾子串无此问题。
精准匹配方案
使用range(of:options:)并指定.literal选项,强制进行字面量精确匹配,严格按照Unicode标量序列比对字符串,避免语言感知的等价替换。
修改后的代码:
var s = "அவர்கள்" var ss1 = "அவர்" // 使用.literal选项进行精确匹配 if let r1 = s.range(of: ss1, options: .literal)?.upperBound { print(s[..<r1]) } else { print("ERROR: substring", ss1, "not found in string", s) }
验证结果
对所有测试案例进行验证,均符合预期:
s = "அவர்கள்", ss1 = "அவர்"→ 匹配成功,输出அவர்s = "அவரகள்", ss1 = "அவர்"→ 匹配失败(正确,无Pulli修饰符)s = "அவராகள்", ss1 = "அவர்"→ 匹配失败(正确,带长元音而非Pulli)s = "அவரிகள்", ss1 = "அவர்"→ 匹配失败(正确,带短元音而非Pulli)s = "அவரைகள்", ss1 = "அவர்"→ 匹配失败(正确,带双元音而非Pulli)
内容的提问来源于stack exchange,提问作者baskaran
相关产品推荐
相关产品推荐

