检查string中是否包含表情符号

我正在用这个string的文本大小

textSize = [[tempDict valueForKeyPath:@"caption.text"] sizeWithFont:[UIFont systemFontOfSize:12] constrainedToSize:CGSizeMake(280, CGFLOAT_MAX) lineBreakMode: NSLineBreakByWordWrapping]; 

我唯一的问题是,如果string只包含一个表情符号,我的应用程序崩溃。 有没有简单的方法来检查表情符号,还是我必须创build一个所有可能的表情符号,然后检查他们使用?

错误:

 -[NSNull sizeWithFont:constrainedToSize:lineBreakMode:]: unrecognized selector sent to instance 0x3aa88a60 if ([tempDict valueForKeyPath:@"caption.text"]){ NSLog(@"%@", [tempDict valueForKeyPath:@"caption"]); //Measure the message label box height textSize = [[tempDict valueForKeyPath:@"caption.text"] sizeWithFont:[UIFont systemFontOfSize:12] constrainedToSize:CGSizeMake(280, CGFLOAT_MAX) lineBreakMode: NSLineBreakByWordWrapping]; int height = 320 + 20 + textSize.height; [cellHeight addObject:[NSNumber numberWithInt:height]]; } 

试试这个代码:

 - (BOOL)stringContainsEmoji:(NSString *)string { __block BOOL returnValue = NO; [string enumerateSubstringsInRange:NSMakeRange(0, [string length]) options:NSStringEnumerationByComposedCharacterSequences usingBlock: ^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) { const unichar hs = [substring characterAtIndex:0]; // surrogate pair if (0xd800 <= hs && hs <= 0xdbff) { if (substring.length > 1) { const unichar ls = [substring characterAtIndex:1]; const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000; if (0x1d000 <= uc && uc <= 0x1f77f) { returnValue = YES; } } } else if (substring.length > 1) { const unichar ls = [substring characterAtIndex:1]; if (ls == 0x20e3) { returnValue = YES; } } else { // non surrogate if (0x2100 <= hs && hs <= 0x27ff) { returnValue = YES; } else if (0x2B05 <= hs && hs <= 0x2b07) { returnValue = YES; } else if (0x2934 <= hs && hs <= 0x2935) { returnValue = YES; } else if (0x3297 <= hs && hs <= 0x3299) { returnValue = YES; } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50) { returnValue = YES; } } }]; return returnValue; } 

@ Simha.IC答案很好。

但是它不适用于新的iOS 9.1表情符号。

Simha.IC片段没有检测到这些:
🤐🤑🤒🤓🤔🤕🤖🤗🤘🦀🦁🦂🦃🦄🧀☂️✝️✡️☯️

所以为了解决这个问题,我调整了一些代码,并创build了一个类:

 - (BOOL)emo_containsEmoji { __block BOOL containsEmoji = NO; [self enumerateSubstringsInRange:NSMakeRange(0, [self length]) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) { const unichar hs = [substring characterAtIndex:0]; // surrogate pair if (0xd800 <= hs && hs <= 0xdbff) { if (substring.length > 1) { const unichar ls = [substring characterAtIndex:1]; const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000; if (0x1d000 <= uc && uc <= 0x1f9c0) { containsEmoji = YES; } } } else if (substring.length > 1) { const unichar ls = [substring characterAtIndex:1]; if (ls == 0x20e3 || ls == 0xfe0f || ls == 0xd83c) { containsEmoji = YES; } } else { // non surrogate if (0x2100 <= hs && hs <= 0x27ff) { containsEmoji = YES; } else if (0x2B05 <= hs && hs <= 0x2b07) { containsEmoji = YES; } else if (0x2934 <= hs && hs <= 0x2935) { containsEmoji = YES; } else if (0x3297 <= hs && hs <= 0x3299) { containsEmoji = YES; } else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50) { containsEmoji = YES; } } }]; return containsEmoji; } 

我的类别可以计算:

  • 如果string有表情符号
  • emojis的数量
  • 每个表情符号的范围

我以这个类别为例创build了一个小项目。

我也创build了一个类,也许你想尝试一下。

你可以使用这个新的框架

https://github.com/woxtu/NSString-RemoveEmoji

用法:

 if (string.isIncludingEmoji) { NSLog(@"String Contains Emoji"); } else { NSLog(@"String Doesn't Contains Emoji"); } 

这就是我正在使用的:

 func isAllEmoji(aString: String) -> Bool { for scalar in aString.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 0x0030...0x0039, 0x00A9...0x00AE, 0x203C...0x2049, 0x2122...0x3299, 0x1F004...0x1F251, 0x1F910...0x1F990: break default: return false } } return true } 

我采取了这是缺less一些表情符号范围,然后使用这个表情符号数组通过迭代查找缺less的rantes …没有深入的testing。

如果有任何字符超过0x00ff可能会发生此问题。 换句话说,除了表情符号之外,还有许多Unicode字符可能需要考虑。 为了查看是否有任何Unicode字符(超出扩展ASCII的边界)使用以下内容。

 extension String { var containsUnicodeCharacters: Bool { for scalar in unicodeScalars { if scalar.value > 0x00FF { return true } } return false } } 

请看,这个答案如何获得NSString的大小,当NSString包括表情符号?

如果你只有emojis,那么你不应该使用sizeWithFont 。 使用标签或其他东西。

NSString不适用于Emojis,只有文本。 如果您有表情符号,那么您应该使用[label sizeToFit][label sizeThatFits:]

另外,你可以使用这个代码:

  id text = [tempDict valueForKeyPath:@"caption.text"] if (![text isKindOfClass:[NSNull class]]) { ... } 

因为,你从字典中获得NSNull,但它不等于零,你的条件工作。

人们一次又一次地使用valueForKeyPath而不是objectForKey。 他们都不能解释为什么。 阅读文档。 如果在阅读之后,你可以解释为什么你使用valueForKeyPath(和“我从某处复制它”不是解释),将其更改为objectForKey。

你的问题与Emojis完全没有关系。 在string中检测表情符号的任何尝试都将失败 – 出于简单的原因,您首先没有string,您有[NSNull null]。 这个问题可以通过使用objectForKey来解决 – 你可能会得到零而不是行为更宽容。 或者你仍然得到[NSNull null]。

找出你为什么得到[NSNull null]。 有人把它放在那里。 如果你无法阻止它在那里,那么你需要处理它。

现在,随着iOS 10的新版本,对于下面的emojis它不起作用:

表情符号

下面的代码片段在iOS 9和iOS 10上都经过了testing和testing:

 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 0x1F910...0x1F918, // New Emoticons 0x1F1E6...0x1F1FF, // Flags 0x1F980...0x1F984, 0x1F191...0x1F19A, 0x1F201...0x1F202, 0x1F232...0x1F23A, 0x1F250...0x1F251, 0x23E9...0x23F3, 0x23F8...0x23FA, 0x1F170...0x1F171, 0x1F17E, 0xA9, 0xAE, 0x2122, 0x2328, 0x3030, 0x1F0CF, 0x1F18E, 0x1F9C0: return true default: continue } } return false } } 

如上所述,在您的应用中创build一个string扩展。

可以这样使用:

 if string.containsEmoji { // Do operations here } 

正如你可能已经注意到的,所有这些表情符号检测方法几乎在苹果公司添加新的表情符号时就会中断。

我已经创build了一个CG扫描解决scheme,应该适用于所有当前和所有未来的表情符号: https : //stackoverflow.com/a/14472163/2057171

据我所知,这是在网上任何地方发布的唯一的实际答案。


 -(BOOL)isEmoji:(NSString *)character {//argument can be character or entire string 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; } 

你可以这样使用它:

 NSString *myString = @"Hello this contains 😇 an emoji"; BOOL containsEmoji = [self isEmoji:myString]; if (containsEmoji) { NSLog(@"Contained Emoji"); } else { NSLog(@"Did not contain Emoji"); }