Muszę się dowiedzieć, czy znak w ciągu znaków to emoji.
Na przykład mam tę postać:
let string = "😀"
let character = Array(string)[0]
Muszę się dowiedzieć, czy ta postać to emoji.
Muszę się dowiedzieć, czy znak w ciągu znaków to emoji.
Na przykład mam tę postać:
let string = "😀"
let character = Array(string)[0]
Muszę się dowiedzieć, czy ta postać to emoji.
let character = string[string.index(after: string.startIndex)]
lub let secondCharacter = string[string.index(string.startIndex, offsetBy: 1)]
Odpowiedzi:
To, na co się natknąłem, to różnica między postaciami, skalarami Unicode i glifami.
Na przykład glif 👨👨👧👧 składa się z 7 skalarów Unicode:
Inny przykład, glif 👌🏿 składa się z 2 skalarów Unicode:
Ostatni, glif 1️⃣ zawiera trzy znaki Unicode:
Tak więc podczas renderowania znaków otrzymane glify naprawdę mają znaczenie.
Swift 5.0 i nowsze wersje znacznie ułatwiają ten proces i pozwalają pozbyć się domysłów, które musieliśmy wykonać. Unicode.Scalar
Nowy Property
typ pomaga określić, z czym mamy do czynienia. Jednak te właściwości mają sens tylko podczas sprawdzania innych skalarów w glifie. Dlatego dodamy kilka wygodnych metod do klasy Character, aby nam pomóc.
Aby uzyskać więcej szczegółów, napisałem artykuł wyjaśniający, jak to działa .
W przypadku Swift 5.0 pozostawia następujący wynik:
extension Character {
/// A simple emoji is one scalar and presented to the user as an Emoji
var isSimpleEmoji: Bool {
guard let firstScalar = unicodeScalars.first else { return false }
return firstScalar.properties.isEmoji && firstScalar.value > 0x238C
}
/// Checks if the scalars will be merged into an emoji
var isCombinedIntoEmoji: Bool { unicodeScalars.count > 1 && unicodeScalars.first?.properties.isEmoji ?? false }
var isEmoji: Bool { isSimpleEmoji || isCombinedIntoEmoji }
}
extension String {
var isSingleEmoji: Bool { count == 1 && containsEmoji }
var containsEmoji: Bool { contains { $0.isEmoji } }
var containsOnlyEmoji: Bool { !isEmpty && !contains { !$0.isEmoji } }
var emojiString: String { emojis.map { String($0) }.reduce("", +) }
var emojis: [Character] { filter { $0.isEmoji } }
var emojiScalars: [UnicodeScalar] { filter { $0.isEmoji }.flatMap { $0.unicodeScalars } }
}
Który da następujące wyniki:
"A̛͚̖".containsEmoji // false
"3".containsEmoji // false
"A̛͚̖▶️".unicodeScalars // [65, 795, 858, 790, 9654, 65039]
"A̛͚̖▶️".emojiScalars // [9654, 65039]
"3️⃣".isSingleEmoji // true
"3️⃣".emojiScalars // [51, 65039, 8419]
"👌🏿".isSingleEmoji // true
"🙎🏼♂️".isSingleEmoji // true
"🇹🇩".isSingleEmoji // true
"⏰".isSingleEmoji // true
"🌶".isSingleEmoji // true
"👨👩👧👧".isSingleEmoji // true
"🏴".isSingleEmoji // true
"🏴".containsOnlyEmoji // true
"👨👩👧👧".containsOnlyEmoji // true
"Hello 👨👩👧👧".containsOnlyEmoji // false
"Hello 👨👩👧👧".containsEmoji // true
"👫 Héllo 👨👩👧👧".emojiString // "👫👨👩👧👧"
"👨👩👧👧".count // 1
"👫 Héllœ 👨👩👧👧".emojiScalars // [128107, 128104, 8205, 128105, 8205, 128103, 8205, 128103]
"👫 Héllœ 👨👩👧👧".emojis // ["👫", "👨👩👧👧"]
"👫 Héllœ 👨👩👧👧".emojis.count // 2
"👫👨👩👧👧👨👨👦".isSingleEmoji // false
"👫👨👩👧👧👨👨👦".containsOnlyEmoji // true
W przypadku starszych wersji Swift zapoznaj się z tym streszczeniem zawierającym mój stary kod.
containsOnlyEmoji
sprawdzania. Zaktualizowałem również przykład do Swift 3.0.
Najprostszym, najczystszym i najszybszym sposobem osiągnięcia tego jest po prostu sprawdzenie punktów kodowych Unicode dla każdego znaku w ciągu względem znanych zakresów emoji i dingbatów, na przykład:
extension String {
var containsEmoji: Bool {
for scalar in unicodeScalars {
switch scalar.value {
case 0x1F600...0x1F64F, // Emoticons
0x1F300...0x1F5FF, // Misc Symbols and Pictographs
0x1F680...0x1F6FF, // Transport and Map
0x2600...0x26FF, // Misc symbols
0x2700...0x27BF, // Dingbats
0xFE00...0xFE0F, // Variation Selectors
0x1F900...0x1F9FF, // Supplemental Symbols and Pictographs
0x1F1E6...0x1F1FF: // Flags
return true
default:
continue
}
}
return false
}
}
0x1F900...0x1F9FF
(na Wikipedii). Nie jestem pewien, czy cały zakres należy uznać za emoji.
extension String {
func containsEmoji() -> Bool {
for scalar in unicodeScalars {
switch scalar.value {
case 0x3030, 0x00AE, 0x00A9,// Special Characters
0x1D000...0x1F77F, // Emoticons
0x2100...0x27BF, // Misc symbols and Dingbats
0xFE00...0xFE0F, // Variation Selectors
0x1F900...0x1F9FF: // Supplemental Symbols and Pictographs
return true
default:
continue
}
}
return false
}
}
To jest moja poprawka ze zaktualizowanymi zakresami.
… Wprowadził nowy sposób sprawdzenia dokładnie tego!
Musisz złamać String
w jego Scalars
. Każdy Scalar
ma Property
wartość, która wspiera tę isEmoji
wartość!
Właściwie możesz nawet sprawdzić, czy Skalar jest modyfikatorem Emoji, czy więcej. Sprawdź dokumentację Apple: https://developer.apple.com/documentation/swift/unicode/scalar/properties
Możesz rozważyć sprawdzenie isEmojiPresentation
zamiast isEmoji
, ponieważ Apple stwierdza, co następuje isEmoji
:
Ta właściwość jest prawdziwa dla skalarów, które są domyślnie renderowane jako emoji, a także dla skalarów, które mają inne niż domyślne renderowanie emoji, po których następuje U + FE0F VARIATION SELECTOR-16. Obejmuje to niektóre skalary, które zwykle nie są uważane za emoji.
W ten sposób faktycznie dzieli Emoji na wszystkie modyfikatory, ale jest o wiele prostszy w obsłudze. A ponieważ Swift liczy teraz emotikony z modyfikatorami (np .: 👨👩👧👦, 👨🏻💻, 🏴) jako 1, możesz robić wszelkiego rodzaju rzeczy.
var string = "🤓 test"
for scalar in string.unicodeScalars {
let isEmoji = scalar.properties.isEmoji
print("\(scalar.description) \(isEmoji)"))
}
// 🤓 true
// false
// t false
// e false
// s false
// t false
NSHipster wskazuje ciekawy sposób na zdobycie wszystkich emotikonów:
import Foundation
var emoji = CharacterSet()
for codePoint in 0x0000...0x1F0000 {
guard let scalarValue = Unicode.Scalar(codePoint) else {
continue
}
// Implemented in Swift 5 (SE-0221)
// https://github.com/apple/swift-evolution/blob/master/proposals/0221-character-properties.md
if scalarValue.properties.isEmoji {
emoji.insert(scalarValue)
}
}
scalar.properties.isEmoji scalar.properties.isEmojiPresentation scalar.properties.isEmojiModifier scalar.properties.isEmojiModifierBase scalar.properties.isJoinControl scalar.properties.isVariationSelector
"6".unicodeScalars.first!.properties.isEmoji
oceni jakotrue
Dzięki Swift 5 możesz teraz sprawdzić właściwości Unicode każdego znaku w ciągu. To daje nam wygodną isEmoji
zmienną na każdej literze. Problem polega na tym, isEmoji
że powróci prawda dla każdego znaku, który można przekształcić w 2-bajtowe emoji, na przykład 0-9.
Możemy spojrzeć na zmienną, isEmoji
a także sprawdzić obecność modyfikatora emoji, aby określić, czy niejednoznaczne znaki będą wyświetlane jako emoji.
To rozwiązanie powinno być dużo bardziej przyszłościowe niż oferowane tutaj rozwiązania regex.
extension String {
func containsOnlyEmojis() -> Bool {
if count == 0 {
return false
}
for character in self {
if !character.isEmoji {
return false
}
}
return true
}
func containsEmoji() -> Bool {
for character in self {
if character.isEmoji {
return true
}
}
return false
}
}
extension Character {
// An emoji can either be a 2 byte unicode character or a normal UTF8 character with an emoji modifier
// appended as is the case with 3️⃣. 0x238C is the first instance of UTF16 emoji that requires no modifier.
// `isEmoji` will evaluate to true for any character that can be turned into an emoji by adding a modifier
// such as the digit "3". To avoid this we confirm that any character below 0x238C has an emoji modifier attached
var isEmoji: Bool {
guard let scalar = unicodeScalars.first else { return false }
return scalar.properties.isEmoji && (scalar.value > 0x238C || unicodeScalars.count > 1)
}
}
Dając nam
"hey".containsEmoji() //false
"Hello World 😎".containsEmoji() //true
"Hello World 😎".containsOnlyEmojis() //false
"3".containsEmoji() //false
"3️⃣".containsEmoji() //true
Character("3️⃣").isEmoji // true
gdyCharacter("3").isEmoji // false
Swift 3 Uwaga:
Wygląda na to, że cnui_containsEmojiCharacters
metoda została usunięta lub przeniesiona do innej biblioteki dynamicznej. _containsEmoji
powinien jednak nadal działać.
let str: NSString = "hello😊"
@objc protocol NSStringPrivate {
func _containsEmoji() -> ObjCBool
}
let strPrivate = unsafeBitCast(str, to: NSStringPrivate.self)
strPrivate._containsEmoji() // true
str.value(forKey: "_containsEmoji") // 1
let swiftStr = "hello😊"
(swiftStr as AnyObject).value(forKey: "_containsEmoji") // 1
Swift 2.x:
Niedawno odkryłem prywatny interfejs API, NSString
który udostępnia funkcje wykrywania, czy ciąg zawiera znak Emoji:
let str: NSString = "hello😊"
Z protokołem objc i unsafeBitCast
:
@objc protocol NSStringPrivate {
func cnui_containsEmojiCharacters() -> ObjCBool
func _containsEmoji() -> ObjCBool
}
let strPrivate = unsafeBitCast(str, NSStringPrivate.self)
strPrivate.cnui_containsEmojiCharacters() // true
strPrivate._containsEmoji() // true
Z valueForKey
:
str.valueForKey("cnui_containsEmojiCharacters") // 1
str.valueForKey("_containsEmoji") // 1
W przypadku czystej struny Swift musisz zarzucić strunę tak, jak AnyObject
przed użyciem valueForKey
:
let str = "hello😊"
(str as AnyObject).valueForKey("cnui_containsEmojiCharacters") // 1
(str as AnyObject).valueForKey("_containsEmoji") // 1
Metody znalezione w pliku nagłówkowym NSString .
Możesz użyć tego przykładu kodu lub tego pod .
Aby użyć go w Swift, zaimportuj kategorię do YourProject_Bridging_Header
#import "NSString+EMOEmoji.h"
Następnie możesz sprawdzić zakres każdego emoji w swoim ciągu:
let example: NSString = "string👨👨👧👧with😍emojis✊🏿" //string with emojis
let containsEmoji: Bool = example.emo_containsEmoji()
print(containsEmoji)
// Output: ["true"]
Z biegiem lat te rozwiązania do wykrywania emoji wciąż się psują, gdy Apple dodaje nowe emoji w / nowe metody (takie jak emoji o odcieniu skóry zbudowane przez wstępne przeklinanie postaci z dodatkową postacią) itp.
W końcu się zepsułem i właśnie napisałem następującą metodę, która działa dla wszystkich obecnych emoji i powinna działać dla wszystkich przyszłych emoji.
Rozwiązanie tworzy UILabel z postacią i czarnym tłem. Następnie CG robi migawkę etykiety i skanuję wszystkie piksele w migawce w poszukiwaniu jakichkolwiek innych niż jednolicie czarne piksele. Powodem dodania czarnego tła jest uniknięcie problemów z fałszywym kolorowaniem z powodu renderowania subpikseli
Rozwiązanie działa BARDZO szybko na moim urządzeniu, mogę sprawdzić setki znaków na sekundę, ale należy zauważyć, że jest to rozwiązanie CoreGraphics i nie powinno być używane tak intensywnie, jak w przypadku zwykłej metody tekstowej. Przetwarzanie grafiki wymaga dużej ilości danych, więc sprawdzenie tysięcy znaków jednocześnie może spowodować zauważalne opóźnienie.
-(BOOL)isEmoji:(NSString *)character {
UILabel *characterRender = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
characterRender.text = character;
characterRender.font = [UIFont fontWithName:@"AppleColorEmoji" size:12.0f];//Note: Size 12 font is likely not crucial for this and the detector will probably still work at an even smaller font size, so if you needed to speed this checker up for serious performance you may test lowering this to a font size like 6.0
characterRender.backgroundColor = [UIColor blackColor];//needed to remove subpixel rendering colors
[characterRender sizeToFit];
CGRect rect = [characterRender bounds];
UIGraphicsBeginImageContextWithOptions(rect.size,YES,0.0f);
CGContextRef contextSnap = UIGraphicsGetCurrentContext();
[characterRender.layer renderInContext:contextSnap];
UIImage *capturedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGImageRef imageRef = [capturedImage CGImage];
NSUInteger width = CGImageGetWidth(imageRef);
NSUInteger height = CGImageGetHeight(imageRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
NSUInteger bytesPerPixel = 4;//Note: Alpha Channel not really needed, if you need to speed this up for serious performance you can refactor this pixel scanner to just RGB
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(rawData, width, height,
bitsPerComponent, bytesPerRow, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);
BOOL colorPixelFound = NO;
int x = 0;
int y = 0;
while (y < height && !colorPixelFound) {
while (x < width && !colorPixelFound) {
NSUInteger byteIndex = (bytesPerRow * y) + x * bytesPerPixel;
CGFloat red = (CGFloat)rawData[byteIndex];
CGFloat green = (CGFloat)rawData[byteIndex+1];
CGFloat blue = (CGFloat)rawData[byteIndex+2];
CGFloat h, s, b, a;
UIColor *c = [UIColor colorWithRed:red green:green blue:blue alpha:1.0f];
[c getHue:&h saturation:&s brightness:&b alpha:&a];//Note: I wrote this method years ago, can't remember why I check HSB instead of just checking r,g,b==0; Upon further review this step might not be needed, but I haven't tested to confirm yet.
b /= 255.0f;
if (b > 0) {
colorPixelFound = YES;
}
x++;
}
x=0;
y++;
}
return colorPixelFound;
}
AppleColorEmoji
, dodając to teraz jako zabezpieczenie przed awarią, chociaż myślę, że Apple i tak zrobi to domyślnie
W przypadku Swift 3.0.2 następująca odpowiedź jest najprostsza:
class func stringContainsEmoji (string : NSString) -> Bool
{
var returnValue: Bool = false
string.enumerateSubstrings(in: NSMakeRange(0, (string as NSString).length), options: NSString.EnumerationOptions.byComposedCharacterSequences) { (substring, substringRange, enclosingRange, stop) -> () in
let objCString:NSString = NSString(string:substring!)
let hs: unichar = objCString.character(at: 0)
if 0xd800 <= hs && hs <= 0xdbff
{
if objCString.length > 1
{
let ls: unichar = objCString.character(at: 1)
let step1: Int = Int((hs - 0xd800) * 0x400)
let step2: Int = Int(ls - 0xdc00)
let uc: Int = Int(step1 + step2 + 0x10000)
if 0x1d000 <= uc && uc <= 0x1f77f
{
returnValue = true
}
}
}
else if objCString.length > 1
{
let ls: unichar = objCString.character(at: 1)
if ls == 0x20e3
{
returnValue = true
}
}
else
{
if 0x2100 <= hs && hs <= 0x27ff
{
returnValue = true
}
else if 0x2b05 <= hs && hs <= 0x2b07
{
returnValue = true
}
else if 0x2934 <= hs && hs <= 0x2935
{
returnValue = true
}
else if 0x3297 <= hs && hs <= 0x3299
{
returnValue = true
}
else if hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50
{
returnValue = true
}
}
}
return returnValue;
}
Absolutnie podobna odpowiedź do tych, które napisałem przede mną, ale z zaktualizowanym zestawem skalarów emoji.
extension String {
func isContainEmoji() -> Bool {
let isContain = unicodeScalars.first(where: { $0.isEmoji }) != nil
return isContain
}
}
extension UnicodeScalar {
var isEmoji: Bool {
switch value {
case 0x1F600...0x1F64F,
0x1F300...0x1F5FF,
0x1F680...0x1F6FF,
0x1F1E6...0x1F1FF,
0x2600...0x26FF,
0x2700...0x27BF,
0xFE00...0xFE0F,
0x1F900...0x1F9FF,
65024...65039,
8400...8447,
9100...9300,
127000...127600:
return true
default:
return false
}
}
}
Możesz użyć NSString-RemoveEmoji w ten sposób:
if string.isIncludingEmoji {
}
Na wspomniane zadanie jest fajne rozwiązanie . Ale sprawdzenie właściwości Unicode.Scalar.Properties skalarów Unicode jest dobre dla pojedynczego znaku. I nie jest wystarczająco elastyczny dla Strings.
Zamiast tego możemy użyć wyrażeń regularnych - bardziej uniwersalne podejście. Poniżej znajduje się szczegółowy opis tego, jak to działa. I oto rozwiązanie.
W Swift możesz sprawdzić, czy String jest pojedynczym znakiem Emoji, używając rozszerzenia z taką obliczoną właściwością:
extension String {
var isSingleEmoji : Bool {
if self.count == 1 {
let emodjiGlyphPattern = "\\p{RI}{2}|(\\p{Emoji}(\\p{EMod}|\\x{FE0F}\\x{20E3}?|[\\x{E0020}-\\x{E007E}]+\\x{E007F})|[\\p{Emoji}&&\\p{Other_symbol}])(\\x{200D}(\\p{Emoji}(\\p{EMod}|\\x{FE0F}\\x{20E3}?|[\\x{E0020}-\\x{E007E}]+\\x{E007F})|[\\p{Emoji}&&\\p{Other_symbol}]))*"
let fullRange = NSRange(location: 0, length: self.utf16.count)
if let regex = try? NSRegularExpression(pattern: emodjiGlyphPattern, options: .caseInsensitive) {
let regMatches = regex.matches(in: self, options: NSRegularExpression.MatchingOptions(), range: fullRange)
if regMatches.count > 0 {
// if any range found — it means, that that single character is emoji
return true
}
}
}
return false
}
}
Pojedynczy emoji (glif) można odtworzyć za pomocą wielu różnych symboli, sekwencji i ich kombinacji. Specyfikacja Unicode definiuje kilka możliwych reprezentacji znaków Emoji.
Znak Emoji odtwarzany przez pojedynczy skalar Unicode.
Unicode definiuje znak Emoji jako:
emoji_character := \p{Emoji}
Ale niekoniecznie oznacza to, że taka postać zostanie narysowana jako Emoji. Zwykły symbol liczbowy „1” ma właściwość Emoji, która ma wartość true, chociaż nadal może być narysowany jako tekst. I jest lista takich symboli: #, ©, 4 itd.
Należy pomyśleć, że możemy wykorzystać dodatkową właściwość do zaznaczenia: „Emoji_Presentation”. Ale to tak nie działa. Istnieje emoji, takie jak 🏟 lub 🛍, które mają właściwość Emoji_Presentation = false.
Aby mieć pewność, że postać jest domyślnie rysowana jako Emoji, powinniśmy sprawdzić jej kategorię: powinna to być „Inny_symbol”.
Tak więc w rzeczywistości wyrażenie regularne dla emoji jednoznakowych powinno być zdefiniowane jako:
emoji_character := \p{Emoji}&&\p{Other_symbol}
Znak, który normalnie można narysować jako tekst lub jako emoji. Jego wygląd uzależniony jest od specjalnego symbolu następującego po nim, selektora prezentacji, który wskazuje typ prezentacji. \ x {FE0E} definiuje reprezentację tekstu. \ x {FE0F} definiuje reprezentację emoji.
Listę takich symboli można znaleźć [tutaj] ( https://unicode.org/Public/emoji/12.1/emoji-variation-sequences.txt ).
Unicode definiuje sekwencję prezentacji w następujący sposób:
emoji_presentation_sequence := emoji_character emoji_presentation_selector
Sekwencja wyrażeń regularnych:
emoji_presentation_sequence := \p{Emoji} \x{FE0F}
Sekwencja wygląda bardzo podobnie jak sekwencja prezentacji, ale ma na końcu dodatkowy skalar: \ x {20E3}. Zakres możliwych do tego bazowych skalarów jest dość wąski: 0-9 # * - i to wszystko. Przykłady: 1️⃣, 8️⃣, * ️⃣.
Unicode definiuje sekwencję klawiszy w następujący sposób:
emoji_keycap_sequence := [0-9#*] \x{FE0F 20E3}
Wyrażenie regularne:
emoji_keycap_sequence := \p{Emoji} \x{FE0F} \x{FE0F}
Niektóre emotikony mogą mieć zmodyfikowany wygląd, podobny do odcienia skóry. Na przykład Emoji 🧑 może być inne: 🧑🧑🏻🧑🏼🧑🏽🧑🏾🧑🏿. Aby zdefiniować Emoji, które w tym przypadku nazywa się „Emoji_Modifier_Base”, można użyć kolejnego „Emoji_Modifier”.
Generalnie taka sekwencja wygląda następująco:
emoji_modifier_sequence := emoji_modifier_base emoji_modifier
Aby to wykryć, możemy wyszukać sekwencję wyrażeń regularnych:
emoji_modifier_sequence := \p{Emoji} \p{EMod}
Flagi to emotikony o określonej strukturze. Każda flaga jest reprezentowana przez dwa symbole „Regional_Indicator”.
Unicode definiuje je tak:
emoji_flag_sequence := regional_indicator regional_indicator
Na przykład flaga Ukrainy 🇺🇦 w rzeczywistości jest reprezentowana przez dwa skalary: \ u {0001F1FA \ u {0001F1E6}
Wyrażenie regularne:
emoji_flag_sequence := \p{RI}{2}
Sekwencja wykorzystująca tak zwaną podstawę_tagu, po której następuje niestandardowa specyfikacja znacznika złożona z zakresu symboli \ x {E0020} - \ x {E007E} i zakończona znacznikiem końca_tagu \ x {E007F}.
Unicode definiuje to następująco:
emoji_tag_sequence := tag_base tag_spec tag_end
tag_base := emoji_character
| emoji_modifier_sequence
| emoji_presentation_sequence
tag_spec := [\x{E0020}-\x{E007E}]+
tag_end := \x{E007F}
Dziwne jest to, że Unicode pozwala na oparcie tagu na emoji_modifier_sequence lub emoji_presentation_sequence w ED-14a . Ale jednocześnie w wyrażeniach regularnych dostarczonych w tej samej dokumentacji wydają się sprawdzać sekwencję na podstawie tylko jednego znaku Emoji.
Na liście Emoji Unicode 12.1 są tylko trzy takie Emoji zdefiniowane . Wszystkie są flagami krajów Wielkiej Brytanii: Anglii 🏴, Szkocji 🏴 i Walii 🏴. Wszystkie są oparte na jednej postaci Emoji. Więc lepiej sprawdźmy tylko taką sekwencję.
Wyrażenie regularne:
\p{Emoji} [\x{E0020}-\x{E007E}]+ \x{E007F}
Łącznik o zerowej szerokości to wartość skalarna \ x {200D}. Z jego pomocą kilka postaci, które są już same w sobie Emoji, można połączyć w nowe.
Na przykład „rodzina z ojcem, synem i córką” Emoji 👨👧👦 jest reprodukowana przez połączenie emotikonów ojciec 👨, córka 👧 i syn 👦 sklejone z symbolami ZWJ.
Dozwolone jest łączenie ze sobą elementów, którymi są pojedyncze znaki Emoji, sekwencje Prezentacji i Modyfikatorów.
Wyrażenie regularne dla takiej sekwencji ogólnie wygląda następująco:
emoji_zwj_sequence := emoji_zwj_element (\x{200d} emoji_zwj_element )+
Wszystkie wymienione powyżej reprezentacje Emoji można opisać za pomocą jednego wyrażenia regularnego:
\p{RI}{2}
| ( \p{Emoji}
( \p{EMod}
| \x{FE0F}\x{20E3}?
| [\x{E0020}-\x{E007E}]+\x{E007F}
)
|
[\p{Emoji}&&\p{Other_symbol}]
)
( \x{200D}
( \p{Emoji}
( \p{EMod}
| \x{FE0F}\x{20E3}?
| [\x{E0020}-\x{E007E}]+\x{E007F}
)
| [\p{Emoji}&&\p{Other_symbol}]
)
)*
miałem ten sam problem i skończyło się na zrobieniu rozszerzenia String
i Character
.
Kod jest zbyt długi, aby go opublikować, ponieważ w rzeczywistości zawiera listę wszystkich emotikonów (z oficjalnej listy Unicode v5.0) w pliku, CharacterSet
który można znaleźć tutaj:
https://github.com/piterwilson/StringEmoji
Zestaw znaków zawierający wszystkie znane emoji (zgodnie z opisem na oficjalnej liście Unicode 5.0 http://unicode.org/emoji/charts-5.0/emoji-list.html )
Określa, czy String
instancja reprezentuje znany pojedynczy znak Emoji
print("".isEmoji) // false
print("😁".isEmoji) // true
print("😁😜".isEmoji) // false (String is not a single Emoji)
var zawieraEmoji: Bool {get}
Określa, czy String
instancja zawiera znany znak Emoji
print("".containsEmoji) // false
print("😁".containsEmoji) // true
print("😁😜".containsEmoji) // true
var unicodeName: String {get}
Stosuje kCFStringTransformToUnicodeName
- CFStringTransform
na kopii String
print("á".unicodeName) // \N{LATIN SMALL LETTER A WITH ACUTE}
print("😜".unicodeName) // "\N{FACE WITH STUCK-OUT TONGUE AND WINKING EYE}"
var niceUnicodeName: String {get}
Zwraca wynik kCFStringTransformToUnicodeName
- CFStringTransform
z usuniętymi \N{
przedrostkami i }
sufiksami
print("á".unicodeName) // LATIN SMALL LETTER A WITH ACUTE
print("😜".unicodeName) // FACE WITH STUCK-OUT TONGUE AND WINKING EYE
Określa, czy Character
instancja reprezentuje znany znak Emoji
print("".isEmoji) // false
print("😁".isEmoji) // true