Skip to content

Instantly share code, notes, and snippets.

@krummler
Last active July 7, 2022 10:39
Show Gist options
  • Save krummler/8aac35e2446d34791ad8e95d792aaa38 to your computer and use it in GitHub Desktop.
Save krummler/8aac35e2446d34791ad8e95d792aaa38 to your computer and use it in GitHub Desktop.
Emoji checking, with some legacy code
import Foundation
extension UnicodeScalar {
/// Note: This method is part of Swift 5, so you can omit this.
/// See: https://developer.apple.com/documentation/swift/unicode/scalar
var isEmoji: Bool {
switch value {
case 0x1F600...0x1F64F, // Emoticons
0x1F300...0x1F5FF, // Misc Symbols and Pictographs
0x1F680...0x1F6FF, // Transport and Map
0x1F1E6...0x1F1FF, // Regional country flags
0x2600...0x26FF, // Misc symbols
0x2700...0x27BF, // Dingbats
0xE0020...0xE007F, // Tags
0xFE00...0xFE0F, // Variation Selectors
0x1F900...0x1F9FF, // Supplemental Symbols and Pictographs
0x1F018...0x1F270, // Various asian characters
0x238C...0x2454, // Misc items
0x20D0...0x20FF: // Combining Diacritical Marks for Symbols
return true
default: return false
}
}
var isZeroWidthJoiner: Bool {
return value == 8205
}
}
extension String {
// Not needed anymore in swift 4.2 and later, using `.count` will give you the correct result
var glyphCount: Int {
let richText = NSAttributedString(string: self)
let line = CTLineCreateWithAttributedString(richText)
return CTLineGetGlyphCount(line)
}
var isSingleEmoji: Bool {
return glyphCount == 1 && containsEmoji
}
var containsEmoji: Bool {
return unicodeScalars.contains { $0.isEmoji }
}
var containsOnlyEmoji: Bool {
return !isEmpty
&& !unicodeScalars.contains(where: {
!$0.isEmoji && !$0.isZeroWidthJoiner
})
}
// The next tricks are mostly to demonstrate how tricky it can be to determine emoji's
// If anyone has suggestions how to improve this, please let me know
var emojiString: String {
return emojiScalars.map { String($0) }.reduce("", +)
}
var emojis: [String] {
var scalars: [[UnicodeScalar]] = []
var currentScalarSet: [UnicodeScalar] = []
var previousScalar: UnicodeScalar?
for scalar in emojiScalars {
if let prev = previousScalar, !prev.isZeroWidthJoiner, !scalar.isZeroWidthJoiner {
scalars.append(currentScalarSet)
currentScalarSet = []
}
currentScalarSet.append(scalar)
previousScalar = scalar
}
scalars.append(currentScalarSet)
return scalars.map { $0.map { String($0) }.reduce("", +) }
}
fileprivate var emojiScalars: [UnicodeScalar] {
var chars: [UnicodeScalar] = []
var previous: UnicodeScalar?
for cur in unicodeScalars {
if let previous = previous, previous.isZeroWidthJoiner, cur.isEmoji {
chars.append(previous)
chars.append(cur)
} else if cur.isEmoji {
chars.append(cur)
}
previous = cur
}
return chars
}
}
@krummler
Copy link
Author

Gives you the follow results:

"πŸ‘ŒπŸΏ".isSingleEmoji // true
"πŸ™ŽπŸΌβ€β™‚οΈ".isSingleEmoji // true
"πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘§".isSingleEmoji // true
"πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘§".containsOnlyEmoji // true
"Hello πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘§".containsOnlyEmoji // false
"Hello πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘§".containsEmoji // true
"πŸ‘« HΓ©llo πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘§".emojiString // "πŸ‘«πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘§"
"πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘§".glyphCount // 1
"πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘§".characters.count // 4, Will return '1' in Swift 4.2 so previous method not needed anymore
"πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘§".count // 4, Will return '1' in Swift 4.2 so previous method not needed anymore

"πŸ‘« HΓ©llΕ“ πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘§".emojiScalars // [128107, 128104, 8205, 128105, 8205, 128103, 8205, 128103]
"πŸ‘« HΓ©llΕ“ πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘§".emojis // ["πŸ‘«", "πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘§"]

"πŸ‘«πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘§πŸ‘¨β€πŸ‘¨β€πŸ‘¦".isSingleEmoji // false
"πŸ‘«πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘§πŸ‘¨β€πŸ‘¨β€πŸ‘¦".containsOnlyEmoji // true
"πŸ‘«πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘§πŸ‘¨β€πŸ‘¨β€πŸ‘¦".glyphCount // 3
"πŸ‘«πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘§πŸ‘¨β€πŸ‘¨β€πŸ‘¦".characters.count // 8, Will return '3' in Swift 4.2 so previous method not needed anymore

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment