NSAttributedString和emoji:位置和长度问题 [英] NSAttributedString and emojis: issue with positions and lengths
问题描述
我正在使用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代码单元的集合。
pos
和
是Unicode标量视图的索引。
另一方面,NSMutableAttributedString
的addAttribute()
方法取一个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屋!