4

Why method isEmojiPresentation return false?

"".unicodeScalars.first?.properties.isEmoji // Optional(false)

"".unicodeScalars.first?.properties.isEmojiPresentation // Optional(false)

enter image description here

Docs

isEmoji - https://developer.apple.com/documentation/swift/unicode/scalar/properties-swift.struct/isemoji

isEmojiPresentation - https://developer.apple.com/documentation/swift/unicode/scalar/properties-swift.struct/isemojipresentation

UDP:

enter image description here

Anastasiia
  • 114
  • 5
  • 3
    What version of iOS are you running the code on? As far as I know, only iOS 15.4+ recognises this as an emoji. – Sweeper Jun 29 '22 at 12:13
  • 1
    @Sweeper what should I do for any IOS version? How I can detect this emoji? – Anastasiia Jun 29 '22 at 12:29
  • 1
    Well then it is on *you* to provide an updated list of emoji characters. Find such a list, either online or locally, and search through it - see if the character is in that list. You can also say something like `it.properties.isEmojiPresentation || CharacterSet(charactersIn: "").contains(it)`, and you can include all the emojis you want to detect, but which are not available in the iOS versions you want to support, in that character set. – Sweeper Jun 29 '22 at 12:37
  • 4
    That said, why do *you* want to treat this as an emoji when even the OS doesn't? That seems like an odd thing to do. Anyway, here is the [Emoji 14.0 Data Files](http://unicode.org/Public/emoji/14.0/) – Sweeper Jun 29 '22 at 12:38
  • @Sweeper how about this? `emoji-test.txt` E14.0 dotted line face – Anastasiia Jun 29 '22 at 13:27

2 Answers2

3

From the isEmoji documentation you posted:

testing isEmoji alone on a single scalar is insufficient to determine if a unit of text is rendered as an emoji; a correct test requires inspecting multiple scalars in a Character.

Therefore, you can use following code to check if there is an emoji presentation:

"".unicodeScalars.contains(where: { $0.properties.isEmoji }) // true
"5".unicodeScalars.contains(where: { $0.properties.isEmoji }) // true, as expected (5️⃣)
"a".unicodeScalars.contains(where: { $0.properties.isEmoji }) // false

and this code to check if the default is the emoji presentation:

"".unicodeScalars.contains(where: { $0.properties.isEmojiPresentation }) // true
"5".unicodeScalars.contains(where: { $0.properties.isEmojiPresentation }) // false
"a".unicodeScalars.contains(where: { $0.properties.isEmojiPresentation }) // false

Here is an extension for convenience:

extension Character {
    var hasEmojiPresentation: Bool {
        unicodeScalars.contains(where: { $0.properties.isEmoji })
    }

    var hasEmojiPresentationAsDefault: Bool {
        unicodeScalars.contains(where: { $0.properties.isEmojiPresentation })
    }
}

Usage:

Character("").hasEmojiPresentation // true
Character("").hasEmojiPresentationAsDefault // true

Character("5").hasEmojiPresentation // true
Character("5").hasEmojiPresentationAsDefault // false

Character("a").hasEmojiPresentation // false
Character("a").hasEmojiPresentationAsDefault // false

Note: The outcome may be different depending on the used Xcode version, since they contain different sets of emojis.

Daniel
  • 20,420
  • 10
  • 92
  • 149
  • I ran your code but got a different result. (updated the question) What Xcode version do you have? Swift? – Anastasiia Jun 29 '22 at 15:22
  • @Anastasiia are you using the character `\u{0001FAE5}`? (you can check with `Array(Character("").unicodeScalars)`). I'm using the playground of Xcode 13.4.1. – Daniel Jun 29 '22 at 15:40
  • Also, maybe make sure that it is not using previous results and it executes correctly (aka. "have you tried turning it off and on again") – Daniel Jun 29 '22 at 15:46
  • yes, it is. I get result: Array(Character("").unicodeScalars) `[129765]` "".unicodeScalars.first?.debugDescription `""\\u{0001FAE5}""` "\u{0001FAE5}" ` ""` I do it in playground of Xcode 13.2 Ok, I created a new playground with it, but result didn't change – Anastasiia Jun 29 '22 at 19:02
  • That emoji wasn’t introduced until [iOS 15.4](https://emojipedia.org/apple/ios-15.4/new/), which is why it doesn’t have an emoji representation on Xcode 13.2. Try an older emoji, such as . – Daniel Jun 29 '22 at 21:17
0

Checking only isEmoji or isEmojiPresentation is not enough to know how a character in text will be presented to the user. You also (at least)* need to check whether there are variation selectors in the character that change how it should be presented. For example, some emoji are presented as text by default, but there is a scalar that can be added to present them as an image, and often when an emoji is input from the user (e.g. ️), it is this emoji+variation sequence that is being generated. I'm sure the opposite example also exists, i.e. image by default but text variation specified.

Here's the code I'm using to detect if a character will be presented as an emoji image:

fileprivate let TEXT_VARIATION_SELECTOR = "\u{FE0E}".unicodeScalars.first
fileprivate let EMOJI_VARIATION_SELECTOR = "\u{FE0F}".unicodeScalars.first

extension Character {
    var presentsEmoji: Bool {
        var emojiByDefault = false
        for s in unicodeScalars {
            if s.properties.isEmojiPresentation { emojiByDefault = true }
            if s == EMOJI_VARIATION_SELECTOR { return true }
            if s == TEXT_VARIATION_SELECTOR { return false }
        }
        return emojiByDefault
    }
}

* I say "at least" because I'm not an expert on Unicode. I've figured out enough that the above satisfies my main use case, whereas trying to just use isEmoji and isEmojiPresentation did not.

Graham Lea
  • 5,797
  • 3
  • 40
  • 55
  • FWIW, there's some much more detailed answers on this question, but for many of them I'm not convinced they are actually good approaches as they seem to rely on character code point ranges. https://stackoverflow.com/questions/30757193/find-out-if-character-in-string-is-emoji – Graham Lea Jul 19 '23 at 04:38