【问题标题】:Swift: NSAttributedString & emojis斯威夫特:NSAttributedString 和表情符号
【发布时间】:2019-06-06 03:59:53
【问题描述】:

我使用启用了文本属性编辑的UITextView,当文本中有表情符号时,我在获取属性时遇到问题。

这是我使用的代码:

var textAttributes = [(attributes: [NSAttributedString.Key: Any], range: NSRange)]()
let range = NSRange(location: 0, length: textView.attributedText.length)
textView.attributedText.enumerateAttributes(in: range) { dict, range, _ in
    textAttributes.append((attributes: dict, range: range))
}

for attribute in textAttributes {
    if let swiftRange = Range(attribute.range, in: textView.text) {
        print("NSRange \(attribute.range): \(textView.text![swiftRange])")
    } else {
        print("NSRange \(attribute.range): cannot convert to Swift range")
    }
}

当我尝试使用“示例文本❤️”之类的文本时,输出如下:

NSRange {0, 12}:示例文本

NSRange {12, 1}:无法转换为 Swift 范围

NSRange {13, 1}:无法转换为 Swift 范围

如您所见,我无法获取包含表情符号的文本。

文本属性由我在文本视图上应用的自定义NSTextStorage 设置。这是setAttributes 方法:

override func setAttributes(_ attrs: [NSAttributedString.Key: Any]?, range: NSRange) {
    guard (range.location + range.length - 1) < string.count  else {
        print("Range out of bounds")
        return
    }

    beginEditing()
    storage.setAttributes(attrs, range: range)
    edited(.editedAttributes, range: range, changeInLength: 0)
    endEditing()
}

请注意,在编辑我的文本视图期间,我有一些“范围超出范围”的打印。

有没有办法将 NSRange 转换为有效的 Swift Range

【问题讨论】:

  • “有没有办法将 NSRange 转换为有效的 Swift Range?” - 您正在使用 Range(attribute.range, in: textView.text) 进行此操作。
  • guard (range.location + range.length - 1) &lt; string.count else { 必须是 guard (range.location + range.length - 1) &lt; string.utf16.count else {
  • @rmaddy 谢谢你,string.utf16.count 工作了!但是,转换为 Swift Range 仍然会写“无法转换为 Swift 范围”。我成功地使用textView.attributedText.attributedSubstring(from: attribute.range).string
  • 某处你有一个 NSRange 可能基于 Swift String 计数,这是错误的。从String 创建NSRange 时,它必须始终为.utf16.count。因此,再次展示您如何将属性应用于属性文本(并展示您如何创建范围)。
  • 非常感谢,我将NSRange 中的所有.count 更改为.utf16.count,它按预期工作!

标签: ios swift nsattributedstring emoji nsrange


【解决方案1】:

使用NSAttributedStringNSRangeString 时要记住的最重要的一点是NSAttributedString(和NSString)和NSRange 基于UTF-16 编码长度。但String 及其count 是基于实际字符数。它们不会混合。

如果您尝试使用someSwiftString.count 创建NSRange,您将得到错误的范围。始终使用someSwiftString.utf16.count

在您的特定情况下,由于 NSRange 中的长度错误,您将属性应用于 ❤️ 字符的一半,并且会级联到您看到的错误。

并且在您发布的代码中,您需要更改:

guard (range.location + range.length - 1) < string.count else {

到:

guard (range.location + range.length - 1) < string.utf16.count else {

出于与上述相同的原因。

【讨论】:

  • 太棒了!今天对我有帮助。
猜你喜欢
  • 2017-07-22
  • 2017-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多