Dowiedz się, czy znak w łańcuchu to emoji?
Muszę się dowiedzieć, czy znak w łańcuchu jest emoji.
Na przykład mam taki znak:
let string = "
10 answers
Natknąłem się na różnicę między znakami, skalarami unicode i glifami.
Na przykład glif składa się z 7 skalarów unicode:
- cztery znaki emoji: [8]}pomiędzy każdym emoji znajduje się znak specjalny, który działa jak klej znaków; zobacz specyfikacje, aby uzyskać więcej informacji
Inny przykład, glif składa się z 2 skalarów unicode:
- zwykły Emotikon:
- modyfikator odcienia skóry:
Więc podczas renderowania znaków, powstałe glify naprawdę mają znaczenie.
Szukałem sposobu, aby wykryć, czy ciąg jest dokładnie i tylko jeden emoji. Więc mogę renderować go większy niż normalny tekst(jak wiadomości robi na iOS10 i WhatsApp robi obecnie). Jak opisano powyżej, liczba postaci jest naprawdę bezużyteczna. ("Znak kleju" nie jest również uważany za emoji).
To, co możesz zrobić, to użyć CoreText, aby pomóc Ci podzielić ciąg znaków na glify i policz je. Ponadto chciałbym przenieść część rozszerzenia zaproponowanego przez Arnolda i Sebastiana Lopeza do osobnego rozszerzenia UnicodeScalar
.
Zostawia Ci następujący wynik:
import UIKit
extension UnicodeScalar {
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
0xFE00...0xFE0F, // Variation Selectors
0x1F900...0x1F9FF, // Supplemental Symbols and Pictographs
127000...127600, // Various asian characters
65024...65039, // Variation selector
9100...9300, // Misc items
8400...8447: // Combining Diacritical Marks for Symbols
return true
default: return false
}
}
var isZeroWidthJoiner: Bool {
return value == 8205
}
}
extension String {
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
}
}
Co da Ci następujące wyniki:
"".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
" 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-03 13:39:46
Najprostszym, najczystszym i najszybszym sposobem na to jest sprawdzenie punktów kodu Unicode dla każdego znaku w łańcuchu względem znanych zakresów emoji i dingbats, jak tak:
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
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-27 23:03:24
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, z zaktualizowanymi zakresami.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-18 20:25:50
Swift 3 Uwaga:
Wygląda na to, że metoda cnui_containsEmojiCharacters
została usunięta lub przeniesiona do innej dynamicznej biblioteki. _containsEmoji
nadal powinno 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 prywatne API na NSString
, które ujawnia funkcjonalność do wykrywania, czy łańcuch 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
Z czystym, szybkim sznurkiem, musisz rzucić sznur jako 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 .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-02 00:27:43
Możesz użyć tego kodu przykład 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 dla każdego emoji w Twoim ciągu:
let example: NSString = "stringwithemojis" //string with emojis
let containsEmoji: Bool = example.emo_containsEmoji()
print(containsEmoji)
// Output: ["true"]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-25 23:03:52
Dla Swifta 3.0.2 najprostsza jest następująca odpowiedź:
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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-06 06:15:36
Możesz użyć NSString-RemoveEmoji w następujący sposób:
if string.isIncludingEmoji {
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-10 02:36:14
! Objective-C (można przekonwertować na Swift)
[3]}z biegiem lat te rozwiązania wykrywające emoji ciągle się psują, ponieważ Apple dodaje nowe emoji w/ nowe metody (takie jak emoji w odcieniu skóry zbudowane przez wcześniejsze przeklinanie postaci z dodatkowym znakiem) itp.W końcu się zepsułem i po prostu napisałem następującą metodę, która działa dla wszystkich obecnych emotikon i powinna działać dla wszystkich przyszłych Emotikon.
Rozwiązanie tworzy UILabel ze znakiem i czarnym tłem. CG następnie bierze migawka etykiety i skanuję wszystkie piksele migawki w poszukiwaniu pikseli innych niż stałe-czarne. Powodem, dla którego dodaję czarne tło, jest uniknięcie problemów z fałszywym kolorowaniem z powodu Subpikselowego renderowania
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 mocno, jak można z zwykłą metodą tekstową. Przetwarzanie grafiki jest ciężkie więc sprawdzanie tysięcy znaki naraz 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.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;
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];
b /= 255.0f;
if (b > 0) {
colorPixelFound = YES;
}
x++;
}
x=0;
y++;
}
return colorPixelFound;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-16 20:59:27
Absolutnie podobna odpowiedź do tych, które napisały 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
}
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-10 08:53:43
Miałem ten sam problem i skończyło się na zrobieniu String
i Character
rozszerzeń.
Kod jest zbyt długi, aby go opublikować, ponieważ faktycznie wyświetla wszystkie emotikony (z oficjalnej listy unicode v5. 0) w CharacterSet
można go znaleźć tutaj:
Https://github.com/piterwilson/StringEmoji
Stałe
let emojiCharacterSet: CharacterSetZestaw znaków zawierający wszystkie znane emoji (jak opisano w oficjalnej liście Unicode 5.0 http://unicode.org/emoji/charts-5.0/emoji-list.html )
String
var isEmoji: Bool { get }Czy instancja String
reprezentuje znany pojedynczy znak Emoji
print("".isEmoji) // false
print("".isEmoji) // true
print("".isEmoji) // false (String is not a single Emoji)
var containsEmoji: Bool { get }
Czy instancja String
zawiera znany znak Emoji
print("".containsEmoji) // false
print("".containsEmoji) // true
print("".containsEmoji) // true
var unicodeName: String { get }
Stosuje kCFStringTransformToUnicodeName
- CFStringTransform
na kopii łańcucha
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 przedrostkami \N{
i }
przyrostkami
print("á".unicodeName) // LATIN SMALL LETTER A WITH ACUTE
print("".unicodeName) // FACE WITH STUCK-OUT TONGUE AND WINKING EYE
Znak
var isEmoji: Bool { get }Czy instancja Character
reprezentuje znany znak Emoji
print("".isEmoji) // false
print("".isEmoji) // true
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-24 14:50:21