您如何验证是否支持多代码点表情符号?

How can you verify a multiple code point emoji is supported?

对于上下文,我正在尝试创建从字符串代码点到表情符号的映射,并且需要知道系统是否支持表情符号:

("1F9AE") -> ""
("1FAE0") -> "" (iOS 15.4+) / nil (if below 15.4, since it would show as "")
("1F415-200D-1F9BA") -> "‍"
("1F415-1F9BA") -> nil (since it would normally be "", which isn't a single emoji)

我已经将其用于单代码点案例:

func emoji(for codepoint: String) -> String? {
    guard let int = Int(codepoint, radix: 16),
        let scalar = UnicodeScalar(int),
        scalar.properties.isEmoji
    else { return nil }
    return String(scalar)
}

但是,我不知道对具有多个代码点的 isEmoji 的相应检查是什么。

// assume I had to make these scalars via a `String`
let scalars = [UnicodeScalar(0x1F415)!, UnicodeScalar(0x200D)!, UnicodeScalar(0x1F9BA)!]
let scalarView = String.UnicodeScalarView(scalars)
// How can I check that this `UnicodeScalarView` is for single, supported emoji, since I can't check `isEmoji`?
print(String(scalarView))

例如,"1FAE0-1F3FD" 应该是 nil,因为它不是单个表情符号 ("")。然而,在未来的版本中,融化的脸可能会与皮肤变化一起使用,在这种情况下,它应该 return 那个单一的有效表情符号。

根据表情符号 14.0 的 data files,表情符号可以是基本表情符号、键帽序列、旗帜、修饰符序列或 ZWJ 序列。在每一种情况下,序列中至少有一个代码点 isEmoji returns true,序列将形成一个字形。

因此,您应该首先从 unicode 标量中创建一个字符串:

let scalars = [UnicodeScalar(0x1F415)!, UnicodeScalar(0x200D)!, UnicodeScalar(0x1F9BA)!]
let scalarView = String.UnicodeScalarView(scalars)
let string = String(scalarView)

然后,你可以看看是不是这样的表情:

CTLineGetGlyphCount(CTLineCreateWithAttributedString(
    NSAttributedString(string: string)
)) == 1 && 
string.unicodeScalars.contains { [=11=].properties.isEmoji }

或者,由于您只是想检查表情符号是否可以正常显示,您可以使用CTFontGetGlyphsForCharacters查看Apple Color Emoji 是否支持这些字符。

let font = UIFont(name: "AppleColorEmoji", size: 20)! as CTFont
var text = Array(string.utf16)
var glyphs = Array(repeating: 0 as CGGlyph, count: text.count)
let isEmoji = CTFontGetGlyphsForCharacters(font, &text, &glyphs, text.count) && 
    CTLineGetGlyphCount(CTLineCreateWithAttributedString(
        NSAttributedString(string: string)
    )) == 1

请注意,这两种方法都会 return 误报(non-emojis 就像 ASCII 字母被报告为表情符号),但不会 return 误报。