I'm coloring some parts of a text coming from an API (think "@mention" as on Twitter) using NSAttributedString.
The API gives me the text and an array of entities representing the parts of the text that are mentions (or links, tags, etc) which should be colored.
But sometimes, the coloration is offset because of emojis.
For example, with this text:
"@ericd Some text. @apero"
the API gives:
[ { "text" : "ericd", "len" : 6, "pos" : 0 }, { "text" : "apero", "len" : 6, "pos" : 18 } ]
which I successfully translate to an NSAttributedString using NSRange:
for m in entities.mentions {
let r = NSMakeRange(m.pos, m.len)
myAttributedString.addAttribute(NSForegroundColorAttributeName, value: someValue, range: r)
}
We see that "pos": 18
is correct, this is where "@apero" starts. The colored parts are "@ericd" and "@apero", as expected.
but when some specific combinations of emojis are used in the text, the API does not translate well to NSATtributedString, the coloration is offset:
"@ericd Some text. πΊβπ» @apero"
gives:
[ { "text" : "ericd", "len" : 6, "pos" : 0 }, { "text" : "apero", "len" : 6, "pos" : 22 } ]
"pos": 22
: the API author states that this is correct, and I understand their point of view.
Unfortunately, NSAttributedString does not agree, my coloration is off:
The last characters for the second mention are not colored (because the "pos" is too short because of the emojis?).
As you might have already guessed, I cannot in any way change the way the API behaves, I have to adapt on client side.
Except that... I have no idea what to do. Should I try to detect what kind of emojis are in the text and manually amend the position of mentions when there's a problematic emoji? But what would be the criteria to detect which emoji shifts the position and which doesn't? And how to decide how much offset I need? Maybe the problem is caused by NSAttributedString?
I understand that this is related to the emojis length once composed compared to their length as discrete characters, but... well... I'm lost (sigh).
Note that I've tried to implement a solution similar to this stuff because my API is compatible with this one, but it only worked partially, some emojis were still breaking the indexes: