You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift 5.1正则表达式拆分异常,请求排查原因

问题分析与解决方案:Swift正则拆分字符串时的偏移量错误

这不是Swift正则表达式的Bug,问题出在你的代码里混用了两种完全不同的字符串位置度量体系——Swift原生的扩展字形集群索引和Foundation框架里的UTF-16代码单元位置,导致计算出来的偏移量完全不匹配。

问题根源拆解

  • Swift的String是基于**扩展字形集群(Extended Grapheme Clusters)**设计的:简单说就是你视觉上看到的每个“字符”就算一个单位,count属性返回的就是这个单位的数量。比如你字符串里的“اً”是由两个Unicode标量组合成的一个视觉字符,在Swift里算1个单位,但在UTF-16编码里它占2个代码单元。
  • 而NSRegularExpression返回的匹配范围NSRange,是基于UTF-16代码单元的位置来计算的,和Swift的String.Index不是一一对应的。

你的代码里犯了一个关键错误:直接把NSRange的location(UTF-16位置)当作Swift字符串的Int偏移量来使用,比如self[start ..< end]里的end是匹配到的\n的UTF-16位置(10),但这个位置对应的Swift字符串索引已经跳过了\n本身,导致你截取的前半部分包含了\n,后半部分又跳过了Very High的第一个字符V,最终得到错误的输出。

修复后的代码

要解决这个问题,你需要放弃用Int跟踪位置的方式,改用Swift原生的String.Index来处理,并且把NSRange正确转换为Swift的Range<String.Index>。修改后的split(regex:)方法如下:

func split(regex pattern: String) throws -> [String] {
    let regex = try NSRegularExpression(pattern: pattern, options: [])
    let fullRange = NSRange(startIndex..., in: self)
    let matches = regex.matches(in: self, options: [], range: fullRange)
    
    var parts = [String]()
    var currentStart = startIndex
    
    for match in matches {
        guard let matchRange = Range(match.range, in: self) else {
            continue
        }
        // 添加匹配项之前的子串
        parts.append(String(self[currentStart..<matchRange.start]))
        // 更新起始位置到匹配项的末尾
        currentStart = matchRange.end
    }
    
    // 添加最后剩余的子串
    if currentStart < endIndex {
        parts.append(String(self[currentStart...]))
    }
    
    return parts
}

现在再运行你的测试代码:

print(try! "مرتفع جداً\nVery High".split(regex: "\n"))

就能得到预期的输出:["مرتفع جداً", "Very High"]

内容的提问来源于stack exchange,提问作者Ala'a Al Hallaq

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 16:04:07