Emoji肤色检测

4

根据这篇文章,我尝试将代码从Swift 2.0更新到Swift 5.0,以便检查哪些表情符号有肤色可用或已经存在其他变体。

我的更新代码如下:

extension String {
var emojiSkinToneModifiers: [String] {
    return [ "", "", "", "", "" ]
}

var emojiVisibleLength: Int {
    var count = 0
    enumerateSubstrings(in: startIndex..<endIndex, options: .byComposedCharacterSequences) { (_, _, _, _) in
        count = count + 1
    }
    return count
}

var emojiUnmodified: String {
    if self.count == 0 {
        return ""
    }
    let range = String(self[..<self.index(self.startIndex, offsetBy: 1)])
    return range
}

var canHaveSkinToneModifier: Bool {
    if self.count == 0 {
        return false
    }
    let modified = self.emojiUnmodified + self.emojiSkinToneModifiers[0]
    return modified.emojiVisibleLength == 1
}
}

可以将其与数组一起使用:

let emojis = [ "", "", "" ]
for emoji in emojis {
   if emoji.canHaveSkinToneModifier {
        let unmodified = emoji.emojiUnmodified
        print(emoji)
        for modifier in emoji.emojiSkinToneModifiers {
            print(unmodified + modifier)
        }
    } else {
      print(emoji)
    }
 }

输出:
为没有变体的表情符号分配变体或已有变体的表情符号。
我认为enumerateSubstringsInRange是不正确的,而且self.characters.count现在变成了self.count。相比于Swift 4之前这种方法易于计算一个组合的表情符号,但在这种情况下可能不太有用。我错过了什么吗? 谢谢

我暂时没有答案,但需要注意的是,从Swift 4开始,扩展字形簇被视为单个字符,因此s.emojiVisibleLength的结果与s.count相同(请参见https://dev59.com/ilkT5IYBdhLWcg3wFrkT)。 - Martin R
抱歉,我的意思是在Swift 4(及更高版本)中,表情符号序列被视为单个字符。 - Martin R
@MartinR 我也是这样认为的... 需要一个解决方案。 - Joannes
1个回答

4

一种“hack”的方法是比较一个正确的表情符号(如“”)和一个希望成为表情符号的符号(如“”)的视觉表示。

我已经修改了您的代码,使其能够工作:

extension String {
    static let emojiSkinToneModifiers: [String] =  ["", "", "", "", ""]

    var emojiVisibleLength: Int {
        var count = 0
        let nsstr = self as NSString
        let range = NSRange(location: 0, length: nsstr.length)
        nsstr.enumerateSubstrings(in: range,
                            options: .byComposedCharacterSequences)
        { (_, _, _, _) in

            count = count + 1
        }
        return count
    }

    var emojiUnmodified: String {
        if isEmpty {
            return self
        }
        let string = String(self.unicodeScalars.first!)
        return string
    }

    private static let emojiReferenceSize: CGSize = {
        let size = CGSize(width : CGFloat.greatestFiniteMagnitude,
                          height: CGFloat.greatestFiniteMagnitude)
        let rect = ("" as NSString).boundingRect(with: size,
                                                     options: .usesLineFragmentOrigin,
                                                     context: nil)
        return rect.size
    }()

    var canHaveSkinToneModifier: Bool {
        if isEmpty {
            return false
        }

        let modified = self.emojiUnmodified + String.emojiSkinToneModifiers[0]

        let size = (modified as NSString)
            .boundingRect(with: CGSize(width : CGFloat.greatestFiniteMagnitude,
                                       height: .greatestFiniteMagnitude),
                          options: .usesLineFragmentOrigin,
                          context: nil).size

        return size == String.emojiReferenceSize
    }
}

让我们来试试:

let emojis = [ "", "", "" ]
for emoji in emojis {
    if emoji.canHaveSkinToneModifier {
        let unmodified = emoji.emojiUnmodified
        print(unmodified)
        for modifier in String.emojiSkinToneModifiers {
            print(unmodified + modifier)
        }
    } else {
        print(emoji)
    }
    print("\n")
}

然后就大功告成了!















谢谢,这可能是对 和 的一个想法,但是对已经被修改的表情符号应用肤色修饰符并没有太多意义,比如 。因此,对于像 、 、 之类的未输出内容,请查看我在问题中提供的第一个链接。 - Joannes
从Swift 4开始,计数是“全局的”。一个解决方案可以是像Swift 3一样的“真实”计数的黑客技巧。 - Joannes
@Joannes 在链接中,文章底部应用了肤色::。那么,您是否想要为可能具有肤色修饰符但目前没有的表情符号(如...)应用肤色? - ielyamani
谢谢,今天这是一个解决方案。 - Joannes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接