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

Swift中如何用utf16Offset:in:处理UTF-8字节偏移索引?

解决Swift中UTF-8字节偏移的字符串范围问题(替代弃用的encodedOffset)

Apple弃用了String.Index(encodedOffset:),给出的警告如下:

'init(encodedOffset:)' is deprecated:
encodedOffset has been deprecated as most common usage is incorrect.
Use String.Index(utf16Offset:in:) to achieve the same behavior.

但encodedOffset和utf16Offset并非同一概念——我从外部服务获取的字符串索引是UTF-8字节偏移格式,直接替换会引发错误。

以字符串"👨‍👩‍👧‍👦"为例:它的UTF-8长度为25字节,UTF-16长度仅为11个代码单元。服务器返回的范围是{0, 25}。

原代码可正常截取目标字符串:

let index = String.Index(encodedOffset: 25)
string[string.startIndex..<index] // "👨‍👩‍👧‍👦"

但按照Apple建议替换为String.Index(utf16Offset:in:)后会直接崩溃:

let index = String.Index(utf16Offset: 25, in: string)
string[string.startIndex..<index] // Fatal error: String index range is out of bounds

此处对应的正确utf16Offset应为11而非25,但无法提前计算UTF-8字节偏移对应的UTF-16偏移,尝试String.UTF8View.Index(utf16Offset: 25, in: string)也无效。

查询Swift演进提案后得知存在UTF-8相关方法,但未找到可用接口,最终通过扩展NSMutableAttributedString实现了兼容方案:

extension NSMutableAttributedString {
  func attributedSubstring(utf8Range: NSRange) -> NSAttributedString {
    let range = rangeIn(utf8Range: utf8Range)
    return attributedSubstring(from: range ?? .zero)
  }

  func rangeIn(utf8Range range: NSRange) -> NSRange? {
    let utf8 = string.utf8
    guard let lowerBound = utf8.index(utf8.startIndex, offsetBy: range.location, limitedBy: utf8.endIndex)?.samePosition(in: string.utf16) else { return nil }
    guard let upperBound = utf8.index(lowerBound, offsetBy: range.length, limitedBy: utf8.endIndex)?.samePosition(in: string.utf16) else { return nil }
    return NSRange(lowerBound ..< upperBound, in: string)
  }
}

使用示例

转换UTF-8范围后截取:

let nsmas = NSMutableAttributedString(string: "👨‍👩‍👧‍👦!👩‍👩‍👦‍👦")
if let range = nsmas.rangeIn(utf8Range: NSMakeRange(26, 25)) {
  nsmas.attributedSubstring(from: range) // "👩‍👩‍👦‍👦"
}

或直接调用封装好的方法:

nsmas.attributedSubstring(utf8Range: NSMakeRange(26, 25)) // "👩‍👩‍👦‍👦"

内容的提问来源于stack exchange,提问作者Peter R

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 03:52:34