NSAttributedString 和表情符号:位置和长度问题

2024-05-10

我正在使用 NSAttributedString 对来自 API 的文本的某些部分(如 Twitter 上的“@mention”)进行着色。

API 为我提供了文本和代表文本中应着色的部分(或链接、标签等)的实体数组。

但有时,颜色会因为表情符号而被抵消。


例如,对于以下文本:

“@ericd 一些文字。@apero”

API 给出:

[ { “文本”:“埃里克”, “长度”:6, “位置”:0 }, { “文本”:“阿佩罗”, “长度”:6, “位置”:18 } ]

我使用 NSRange 成功将其转换为 NSAttributedString:

for m in entities.mentions {
    let r = NSMakeRange(m.pos, m.len)
    myAttributedString.addAttribute(NSForegroundColorAttributeName, value: someValue, range: r)
}

我们看到"pos": 18是正确的,这是“@apero”开始的地方。正如预期的那样,彩色部分是“@ericd”和“@apero”。

但是当文本中使用某些特定的表情符号组合时,API 无法很好地转换为 NSATtributedString,颜色会发生偏移:

“@ericd 一些文字。????✌???? @apero”

gives:

[ { “文本”:“埃里克”, “长度”:6, “位置”:0 }, { “文本”:“阿佩罗”, “长度”:6, “位置”:22 } ]

"pos": 22:API作者声明这是正确的,我理解他们的观点。

不幸的是, NSAttributedString 不同意,我的着色关闭了:

第二次提到的最后一个字符没有着色(因为“pos”由于表情符号而太短?)。

正如您可能已经猜到的那样,我无法以任何方式改变 API 的行为方式,我必须在客户端进行调整。

除此之外...我不知道该怎么办。我是否应该尝试检测文本中的表情符号类型,并在出现有问题的表情符号时手动修改提及的位置?但是检测哪些表情符号改变位置、哪些不改变位置的标准是什么?以及如何决定我需要多少补偿?也许问题是由 NSAttributedString 引起的?

我知道这与曾经组成的表情符号长度与它们作为离散字符的长度相比有关,但是......好吧......我迷路了(叹气)。


请注意,我尝试实施类似的解决方案这个东西 https://github.com/berg/ANAPIRangeAdapter/blob/master/ANAPIRangeAdapter/NSString%2BANAPIRangeAdapter.m因为我的 API 与这个兼容,但它只部分工作,一些表情符号仍然破坏索引:


A Swift String对其内容提供不同的“看法”。 一个很好的概述在“Swift 2 中的字符串” https://developer.apple.com/swift/blog/?id=30在斯威夫特博客中:

  • characters是字符值或扩展字素簇的集合。
  • unicodeScalars是 Unicode 标量值的集合。
  • utf8是 UTF-8 代码单元的集合。
  • utf16是 UTF-16 代码单元的集合。

正如讨论中所表明的那样,pos and len从你的API 是 Unicode 标量视图的索引。

另一方面,addAttribute()的方法NSMutableAttributedString需要一个NSRange,即对应的范围 到 UTF-16 代码点的索引NSString.

String提供了在索引之间“翻译”的方法 不同的观点(比较NSRange 到 Range https://stackoverflow.com/questions/25138339/nsrange-to-rangestring-index/30404532#30404532):

let text = "@ericd Some text. ????✌???? @apero"
let pos = 22
let len = 6

// Compute String.UnicodeScalarView indices for first and last position:
let from32 = text.unicodeScalars.index(text.unicodeScalars.startIndex, offsetBy: pos)
let to32 = text.unicodeScalars.index(from32, offsetBy: len)

// Convert to String.UTF16View indices:
let from16 = from32.samePosition(in: text.utf16)
let to16 = to32.samePosition(in: text.utf16)

// Convert to NSRange by computing the integer distances:
let nsRange = NSRange(location: text.utf16.distance(from: text.utf16.startIndex, to: from16),
                      length: text.utf16.distance(from: from16, to: to16))

This NSRange是您需要的属性字符串:

let attrString = NSMutableAttributedString(string: text)
attrString.addAttribute(NSForegroundColorAttributeName,
                        value: UIColor.red,
                        range: nsRange)

Swift 4 (Xcode 9) 更新:在 Swift 4 中,标准库 提供了 Swift 之间转换的方法String范围和NSString范围,因此计算简化为

let text = "@ericd Some text. ????✌???? @apero"
let pos = 22
let len = 6

// Compute String.UnicodeScalarView indices for first and last position:
let fromIdx = text.unicodeScalars.index(text.unicodeScalars.startIndex, offsetBy: pos)
let toIdx = text.unicodeScalars.index(fromIdx, offsetBy: len)

// Compute corresponding NSRange:
let nsRange = NSRange(fromIdx..<toIdx, in: text)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

NSAttributedString 和表情符号:位置和长度问题 的相关文章

  • 自定义相机视图 Swift iOS 8 iPhone Xcode 6.1

    我想在 iPhone 的 View 中使用相机 我不想使用典型的全屏相机视图 而是我自己的 例如 我想在屏幕中间有一个 200x200 的正方形 并且有一个相机预览 在这个方块下面我想要一个拍照按钮 怎么做 我是新手 速度很快 你会想要使用
  • 如何通过 Google Sheets API 进行基本写作?

    在使用 Swift 学习 Google Sheets API 的过程中 我想将单个范围写入电子表格 调查iOS 快速入门指南 https developers google com sheets quickstart ios ver swi
  • 在 Java 中对多语言环境字符串进行排序

    我正在尝试按字符串字段 国家 地区 对对象列表进行排序 每个国家 地区都使用其母语 阿根廷 澳大利亚 奥地利 例如 我想要做的是让 出现在 A 国家之后 因为字母 对应于拉丁语 B 我正在尝试使用默认的 Collat er 但非拉丁名称仍然
  • Java 正则表达式中 \w 和 \b 的 Unicode 等效项?

    许多现代正则表达式实现解释 w字符类简写为 任何字母 数字或连接标点符号 通常 下划线 这样 正则表达式就像 w 匹配像这样的词hello l ve GO 432 or gefr ig 不幸的是 Java 没有 在爪哇 w仅限于 A Za
  • Swift:配对数组元素的最佳方法是什么

    我遇到了一个需要成对迭代数组的问题 最好的方法是什么 或者 作为替代方案 将数组转换为对数组 然后可以正常迭代 的最佳方法是什么 这是我得到的最好的 这个需要output成为一个var 而且它并不是很漂亮 有没有更好的办法 let inpu
  • 更改 macOS 应用程序中打开窗口中的文档

    我正在为 macOS 编写一个基于文档的应用程序 我正在尝试编写一项功能来更改当前窗口中的活动文档 以便能够循环浏览文件夹中的下一个 上一个文档 就像使用图像浏览器应用程序一样 我应该调用什么命令来在当前窗口中打开不同的文档 文档表明 op
  • Twitter api 文本字段值被截断

    为什么文本字段值被截断以及如何获得完整的值 截至目前 我正在尝试获取如下所示的文本字段值 do if let responseObject try NSJSONSerialization JSONObjectWithData respons
  • GM 发布 Xcode 6 编译

    我刚刚下载了 Xcode 6 的 GM 版本 但无法编译并出现以下错误 Command Applications Xcode app Contents Developer Toolchains XcodeDefault xctoolchai
  • 从 UTC 转换为本地时区给出错误结果

    背景我需要将格式为 HH mm 的时间字符串从 UTC 转换为本地时区 例如 如果 UTC 时间为 09 00 则当地时间 斯德哥尔摩 欧洲 应提前两个小时 Problem当我将 09 00 UTC 转换为斯德哥尔摩 欧洲时间时 我得到 1
  • 在有或没有 UNICODE 支持的情况下,如何在我的程序中使用 _stprintf?

    微软的 定义 stprintf as swprintf if UNICODE被定义 并且sprintf如果不 但这些函数采用不同的参数 在swprintf 第二个参数是缓冲区大小 但是sprintf没有这个 有人偷懒了吗 如果是这样 这就是
  • 在 Swift 中对约束进行动画处理

    我有一个UITextField我想在点击时放大它的宽度 我设置了约束 并确保左侧约束的优先级低于我尝试在右侧设置动画的约束 这是我尝试使用的代码 move the input box UIView animateWithDuration 1
  • iOS - 如何在 swift 中使用 `NSMutableString`

    我已经看过这段 Objective C 代码 但我很难在 swift 中做同样的事情 NSMutableAttributedString res self richTextEditor attributedText mutableCopy
  • 如何使用 Vapor 和 Leaf 将图像从浏览器上传到 Amazon S3?

    我已经设置了 AWS S3 存储桶 并且可以使用 Vapor 3 和 Postman 上传文件 PUT request 和标头 x amz acl public read 但我想从浏览器中执行此操作 我使用的是 leaf 那么如何从浏览器上
  • Swift SpriteKit edgeLoopF​​romRect 问题

    下面的代码可以识别底部和顶部边缘场景和球按预期弹开 但是 那左边缘和右边缘现场的情况一直被破坏 如果施加足够的力 球会离开屏幕 然后最终返回 就好像场景的边缘超出了 iPhone 模拟器窗口的边缘 import SpriteKit clas
  • MySQL 与日语字符

    我试图弄清楚如何创建一个表 以便我可以在其中插入日语名字 现在我有 Type InnoDB Encoding UTF 8 Unicode utf8 Collation utf8 general ci 但是 当我插入字符时 它显示为 当我使用
  • 使用未解析的标识符“FlurryAdInterstitial”

    我正在尝试整合Flurry Interstitial Ads使用cocoapods in Swift and Xcode 7 1 1 我正在关注开发人员雅虎网站上的此文档 https developer yahoo com flurry d
  • “预期的 ';'在 Swift 下的顶级声明符之后”

    我正在尝试将所有颜色设置在一个 Swift 文件中 该文件可以在我的整个应用程序中使用 下面的代码会导致 import Foundation import UIKit class DotColors let tsblueColor UICo
  • Mysql插入表后不显示右单引号(’)

    我有一个名为 测试 的表 我插入了一行 其中包含unicode字符右单引号 0x2019在名称字段中 SQL insert into Testing values Sno Name Address insert into Testing v
  • 如何在button.addTarget操作中发送多个按钮?斯威夫特3

    如何将button和button2发送到我的pressButton2函数中 当用户触摸按钮2时 我需要更改按钮和按钮2的颜色 当我的 button2 addTarget 看起来像这样时 我收到错误 表达式列表中存在预期表达式 import
  • 如何更改 SwiftUI 列表中分隔符的颜色?

    我在 SwiftUI 中创建了一个列表 我想更改颜色或删除分隔符 因为在 UIKit 中 我们可以轻松更改 TableView 中分隔符的颜色 下面是 SwiftUI 中列表的代码和 UI 图片 State private var user

随机推荐