NSAttributedString和emoji:位置和长度问题 [英] NSAttributedString and emojis: issue with positions and lengths

查看:0
本文介绍了NSAttributedString和emoji:位置和长度问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用NSAttributedString为来自API的文本的某些部分上色(想象一下Twitter上的"@提及")。

API为我提供了文本和代表文本部分的实体数组,这些部分是应该着色的提及(或链接、标记等)。

但有时,颜色会因为表情符号而偏移。


例如,文本如下:

"@ericd一些文本。@apero"

接口提供:

[ { "Text":"ericd", "len":6, "位置":0 }, { "Text":"apero", "len":6, 《Pos》: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"。

但当文本中使用了某些特定的emoji组合时,API无法很好地转换为NSATtributedString,颜色偏移

"@ericd一些文本。😺✌🏻@apero"

给予:

[ { "Text":"ericd", "len":6, "位置":0 }, { "Text":"apero", "len":6, 《Pos》:22 } ]

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

遗憾的是,NSAttributedString不同意,我的颜色已关闭:

第二个提到的最后一个字符没有上色(因为表情符号"pos"太短了?)。

正如您可能已经猜到的,我无法以任何方式更改API的行为方式,我必须适应客户端。

除了...我不知道该怎么办。我是否应该尝试检测文本中有哪些表情符号,并在存在问题的表情符号时手动修改提及的位置?但是,用什么标准来判断哪个表情符号改变了位置,哪个没有呢?以及如何决定我需要多少补偿?可能该问题是由NSAttributedString引起的?

我理解这与表情符号的长度有关,而表情符号的长度与它们作为独立字符的长度相比,但...嗯..。我迷路了(叹气)。


请注意,我尝试实现了一个类似于this stuff的解决方案,因为我的API与该解决方案兼容,但它只能部分工作,一些emoji表情仍然破坏索引:

推荐答案

SWIFTString为其内容提供不同的"视图"。 SWIFT博客"Strings in Swift 2"中给出了一个很好的概述:

  • characters是字符值或扩展字素簇的集合。
  • unicodeScalars是Unicode标量值的集合。
  • utf8是UTF-8代码单元的集合。
  • utf16是UTF-16代码单元的集合。
如讨论中所示,来自您的API的pos和 是Unicode标量视图的索引。

另一方面,NSMutableAttributedStringaddAttribute()方法取一个NSRange,即对应的范围 设置为NSString中UTF-16码位的索引。

String提供了在 不同的视图(比较NSRange to Range<String.Index>):

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

这是属性字符串所需的NSRange

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

SWIFT 4(Xcode 9)更新:在SWIFT 4中,标准库 提供在SWIFTString范围和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)

这篇关于NSAttributedString和emoji:位置和长度问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆