clozach
clozach

Reputation: 5136

How to compose multi-character emoji from raw hex

I'm getting JSON like this from the server:

{
    "unicode":"1f468-1f468-1f467-1f467"
}

and I'm supposed to translate it into its composite character for display and/or copying to the pasteboard: πŸ‘¨β€πŸ‘¨β€πŸ‘§β€πŸ‘§

The solution so far comes from this SO question:

let u = json["unicode"] as? String
let dashless = u.characters.split{$0 == "-"}.map(String.init)
let charArray = dashless.map { char -> Character in
    let code = Int(strtoul(char, nil, 16))
    return Character(UnicodeScalar(code))
}
let unicode = String(charArray)
UIPasteboard.generalPasteboard().string = unicode

This works great for single-character emoji definitions.

E.g., I can run the code above with this JSON…

{
    "unicode":"1f4a9"
}

…and paste the expected result: πŸ’©. But when I do with the mmgg family emoji listed earlier, I get the following in iOS, minus the spaces: πŸ‘¨β€ πŸ‘¨β€ πŸ‘§β€ πŸ‘§. They just don't seem to want to combine when pasted into a text field.

Is this an iOS bug, or am I doing something wrong?

Upvotes: 3

Views: 1776

Answers (1)

user3441734
user3441734

Reputation: 17534

try this in your playground, to see the difference ...

"πŸ‘¨πŸ‘¨πŸ‘§πŸ‘§".unicodeScalars.forEach { (c) in
    print(c.escape(asASCII: true),terminator: "")
}

print("")

"πŸ‘¨β€πŸ‘¨β€πŸ‘§β€πŸ‘§".unicodeScalars.forEach { (c) in
    print(c.escape(asASCII: true), terminator: "")
}

/*
 \u{0001F468}\u{0001F468}\u{0001F467}\u{0001F467}
 \u{0001F468}\u{200D}\u{0001F468}\u{200D}\u{0001F467}\u{200D}\u{0001F467}
 */

your original, slightly modified code

import Darwin // stroul

let u = "1f468-1f468-1f467-1f467"
let dashless = u.characters.split{$0 == "-"}.map(String.init)
let emoji = dashless.map { char -> String in
    let code = Int(strtoul(char, nil, 16))
    return String(UnicodeScalar(code))
    }.joinWithSeparator("\u{200D}")

print(emoji) // πŸ‘¨β€πŸ‘¨β€πŸ‘§β€πŸ‘§

pure Swift code, no Foundation, without strtoul

let u = "1f468-1f468-1f467-1f467"
let emoji = u.characters.split("-")
    .map {String(UnicodeScalar(Int(String($0),radix: 16) ?? 0))}
    .joinWithSeparator("\u{200D}")

print(emoji) // πŸ‘¨β€πŸ‘¨β€πŸ‘§β€πŸ‘§

Upvotes: 5

Related Questions