我对苹果公司的警告感到有点困惑:

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

因为encodedOffsetutf16Offset不是一回事.在我的例子中,我从外部源获得字符串索引,这些索引是UTF8字节偏移量.

拿这个字符串:"👨‍👩‍👧‍👦".这是25个UTF8字节长.22个utf16字节长(苹果称之为utf16.count 11).

我从服务器收到的是{0, 25}的范围.

以下作品:

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

苹果公司建议将其替换为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,在我得到子字符串之前,无法计算UTF8中的25个字节是11个utf16双字节,因为这取决于字符串的细节.

这也不管用

String.UTF8View.Index(utf16Offset: 25, in: string)

我如何在一个字符串中得到一个utf8字节的偏移量utf16Offset:in:

Swift 5: String.UTF16View.Index(encodedOffset: l) deprecated

这个问题不是上面问题的重复,因为在那个问题中,答案是关于UTF16,而不是UTF8.

GitHub在这里发布的帖子:https://github.com/apple/swift-evolution/blob/main/proposals/0241-string-index-explicit-encoding-offset.md暗示有UTF8替代方案:

/// The UTF-8 code unit offset corresponding to this Index
public func offset<S: StringProtocol>(in utf8: S.UTF8View) -> Int { ... }

但我在其他地方找不到它.

编辑:这是让它为我工作的代码,我不确定为什么我会给那utf16Offset个警告任何信任.

谢谢@伊泰

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)
  }
}

用途:

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

或者只是:

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

推荐答案

因为您显式地使用UTF-8代码单元(字节),所以直接使用String.UTF8View是最有意义的;具体地说,因为UTF8View是UTF-8代码单元的Collection,所以将UTF8View.Index偏移一个数字将使其前进那么多个单位.

给定UTF-8代码单位范围和String,您将实现如下所示:

let (lower, upper) = (0, 25)
let str = "👨‍👩‍👧‍👦 Hello, family!"
let utf8View = str.utf8

let start = utf8View.index(utf8View.startIndex, offsetBy: lower)
let end = utf8View.index(utf8View.startIndex, offsetBy: upper)
print(str[start ..< end]) // => "👨‍👩‍👧‍👦"

在内部,index(_:offsetBy:)操作以一种稳定的方式完成了你正在做的事情:它是fetches the encodedOffset of the index,按照你传入的偏移量前进,然后创建a new index with that encoded offset.这应该与使用已弃用的encodedOffset API一样具有性能,其好处是比"编码偏移量"(这并不意味着什么)更清晰.

如果您发现自己经常执行此操作,您可以编写一些帮助器来执行此操作.

Swift相关问答推荐

Swift Tree实现中的弱var

TabView中的视频播放器意外播放

在visionOS 1.0中已弃用';base Color';:请改用`Color`属性

将`@Environment`值赋给`Binding`参数

与视图交互使工具栏&;标题消失

如何增加 NSStatusBar 图像大小?

如何在应用程序区域永久更改 NSCursor?

If 语句在 Swift 中有 2 个日期

在 struct 中的序列和非序列泛型函数之间进行 Select

这是 Int64 Swift Decoding 多余的吗?

如何获得不同的插入和移除过渡动画?

如何使用 Date.ParseStrategy 在 Swift 5.6 中将字符串解析为日期?

为什么swiftui中的导航视图栏那么大?

在 Swift 4 中实现自定义解码器

将if let与逻辑或运算符一起使用

subscribeOn 和 observeOn 的顺序重要吗?

如何更改弹出框的大小

Swift 3:小数到 Int

Swift :如何在一组字符之后得到所有东西

<<错误类型>> 奇怪的错误