简体   繁体   English

检查字符串中是否包含表情符号

[英]Check if there is an emoji contained in a string

I am getting the text size of a string with this 我用这个获得字符串的文本大小

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

The only problem I have is that if the string only contains an emoji, my app crashes. 我唯一的问题是,如果字符串只包含表情符号,我的应用程序崩溃。 Is there an easy way to check for emojis or do I have to create an array with all possible emojis and then check for them using that? 有没有一种简单的方法来检查表情符号,或者我是否必须创建一个包含所有可能的表情符号的数组,然后使用它来检查它们?

error: 错误:

-[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]];
}

try this code: 试试这段代码:

- (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 answer is great. @Simha.IC答案很棒。

However it does not work with the new iOS 9.1 emojis'. 但它不适用于新的iOS 9.1 emojis'。

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

So to solve the problem I tweaked a little bit the code and created a category with it: 所以为了解决这个问题,我稍微调整了一下代码并用它创建了一个类别:

- (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;
}

My category can calculate: 我的类别可以计算:

  • If the string has emojis 如果字符串有表情符号
  • The number of emojis 表情符号的数量
  • The range for every emoji 每个表情符号的范围

I created a small project with the category as an example. 我创建了一个以类别为例的小项目。

I also created a pod with the category maybe you want to try it. 我还创建了一个类别的pod,也许你想尝试一下。

This is what I'm using: 这就是我正在使用的:

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
}

I took this which was missing some emoji ranges, and then used this emoji array to find missing rantes by iteration... Have not deep tested. 我拿了这个缺少一些表情符号范围,然后使用这个表情符号数组通过迭代找到缺少的rantes ...没有经过深度测试。

You can use this new framework 您可以使用这个新框架

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

Usage: 用法:

if (string.isIncludingEmoji) 
{
   NSLog(@"String Contains Emoji");
}

else
{
  NSLog(@"String Doesn't Contains Emoji");
}

This issue may occur if there are any characters past 0x00ff . 如果有任何字符超过0x00ff可能会发生此问题。 In other words, there are many Unicode characters in addition to Emoji that you may need to account for. 换句话说,除了表情符号之外,还有许多Unicode字符可能需要考虑。 In order to see if there are any Unicode characters (beyond the boundary of extended ASCII) use the following. 为了查看是否有任何Unicode字符(超出扩展ASCII的边界),请使用以下命令。

extension String {

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

}

it's too late reply into this but it's may help someone. 回复此事已经太晚了,但它可能对某人有所帮助。

- (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];
         const unichar ls = substring.length > 1 ? [substring characterAtIndex:1] : 0;

#define IS_IN(val, min, max) (((val) >= (min)) && ((val) <= (max)))

         if(IS_IN(hs, 0xD800, 0xDBFF))
         {
             if(substring.length > 1)
             {
                 const int uc = ((hs - 0xD800) * 0x400) + (ls - 0xDC00) + 0x10000;

                 // Musical: [U+1D000, U+1D24F]
                 // Enclosed Alphanumeric Supplement: [U+1F100, U+1F1FF]
                 // Enclosed Ideographic Supplement: [U+1F200, U+1F2FF]
                 // Miscellaneous Symbols and Pictographs: [U+1F300, U+1F5FF]
                 // Supplemental Symbols and Pictographs: [U+1F900, U+1F9FF]
                 // Emoticons: [U+1F600, U+1F64F]
                 // Transport and Map Symbols: [U+1F680, U+1F6FF]
                 if(IS_IN(uc, 0x1D000, 0x1F9FF))
                     returnValue = YES;
             }
         }
         else if(substring.length > 1 && ls == 0x20E3)
         {
             // emojis for numbers: number + modifier ls = U+20E3
             returnValue = YES;
         }
         else
         {
             if(        // Latin-1 Supplement
                hs == 0x00A9 || hs == 0x00AE
                // General Punctuation
                ||  hs == 0x203C || hs == 0x2049
                // Letterlike Symbols
                ||  hs == 0x2122 || hs == 0x2139
                // Arrows
                ||  IS_IN(hs, 0x2194, 0x2199) || IS_IN(hs, 0x21A9, 0x21AA)
                // Miscellaneous Technical
                ||  IS_IN(hs, 0x231A, 0x231B) || IS_IN(hs, 0x23E9, 0x23F3) || IS_IN(hs, 0x23F8, 0x23FA) || hs == 0x2328 || hs == 0x23CF
                // Geometric Shapes
                ||  IS_IN(hs, 0x25AA, 0x25AB) || IS_IN(hs, 0x25FB, 0x25FE) || hs == 0x25B6 || hs == 0x25C0
                // Miscellaneous Symbols
                ||  IS_IN(hs, 0x2600, 0x2604) || IS_IN(hs, 0x2614, 0x2615) || IS_IN(hs, 0x2622, 0x2623) || IS_IN(hs, 0x262E, 0x262F)
                ||  IS_IN(hs, 0x2638, 0x263A) || IS_IN(hs, 0x2648, 0x2653) || IS_IN(hs, 0x2665, 0x2666) || IS_IN(hs, 0x2692, 0x2694)
                ||  IS_IN(hs, 0x2696, 0x2697) || IS_IN(hs, 0x269B, 0x269C) || IS_IN(hs, 0x26A0, 0x26A1) || IS_IN(hs, 0x26AA, 0x26AB)
                ||  IS_IN(hs, 0x26B0, 0x26B1) || IS_IN(hs, 0x26BD, 0x26BE) || IS_IN(hs, 0x26C4, 0x26C5) || IS_IN(hs, 0x26CE, 0x26CF)
                ||  IS_IN(hs, 0x26D3, 0x26D4) || IS_IN(hs, 0x26D3, 0x26D4) || IS_IN(hs, 0x26E9, 0x26EA) || IS_IN(hs, 0x26F0, 0x26F5)
                ||  IS_IN(hs, 0x26F7, 0x26FA)
                ||  hs == 0x260E || hs == 0x2611 || hs == 0x2618 || hs == 0x261D || hs == 0x2620 || hs == 0x2626 || hs == 0x262A
                ||  hs == 0x2660 || hs == 0x2663 || hs == 0x2668 || hs == 0x267B || hs == 0x267F || hs == 0x2699 || hs == 0x26C8
                ||  hs == 0x26D1 || hs == 0x26FD
                // Dingbats
                ||  IS_IN(hs, 0x2708, 0x270D) || IS_IN(hs, 0x2733, 0x2734) || IS_IN(hs, 0x2753, 0x2755)
                ||  IS_IN(hs, 0x2763, 0x2764) || IS_IN(hs, 0x2795, 0x2797)
                ||  hs == 0x2702 || hs == 0x2705 || hs == 0x270F || hs == 0x2712 || hs == 0x2714 || hs == 0x2716 || hs == 0x271D
                ||  hs == 0x2721 || hs == 0x2728 || hs == 0x2744 || hs == 0x2747 || hs == 0x274C || hs == 0x274E || hs == 0x2757
                ||  hs == 0x27A1 || hs == 0x27B0 || hs == 0x27BF
                // CJK Symbols and Punctuation
                ||  hs == 0x3030 || hs == 0x303D
                // Enclosed CJK Letters and Months
                ||  hs == 0x3297 || hs == 0x3299
                // Supplemental Arrows-B
                ||  IS_IN(hs, 0x2934, 0x2935)
                // Miscellaneous Symbols and Arrows
                ||  IS_IN(hs, 0x2B05, 0x2B07) || IS_IN(hs, 0x2B1B, 0x2B1C) || hs == 0x2B50 || hs == 0x2B55
                )
             {
                 returnValue = YES;
             }
         }

#undef IS_IN
     }];

    return returnValue;
}

Please, see this answer How to get NSString size when NSString includes emojis? 请参阅此答案当NSString包含表情符号时如何获得NSString大小?

If you have only emojis then you shouldn't use sizeWithFont . 如果你只有emojis那么你不应该使用sizeWithFont Use label for it or something else. 使用标签或其他东西。

NSString doesn't work with Emojis, only text. NSString不适用于Emojis,只适用于文本。 If you have emojis, then you should use [label sizeToFit] or [label sizeThatFits:] 如果你有表情符号,那么你应该使用[label sizeToFit][label sizeThatFits:]

Also, you can use this code: 此外,您可以使用此代码:

 id text = [tempDict valueForKeyPath:@"caption.text"]

 if (![text isKindOfClass:[NSNull class]]) {
 ...
 }

Because, you get NSNull from dictionary, but it doesn't equal nil, and your condition works. 因为,你从字典中获得NSNull,但它不等于nil,并且你的条件有效。

Again and again people use valueForKeyPath instead of objectForKey. 人们一次又一次地使用valueForKeyPath而不是objectForKey。 None of them can ever explain why. 他们都无法解释原因。 Read the documentation. 阅读文档。 If after reading it you can explain why you are using valueForKeyPath (and "I copied it from somewhere" is not an explanation), change it to objectForKey. 如果在阅读之后您可以解释为什么使用valueForKeyPath(以及“我从某处复制它”不是解释),请将其更改为objectForKey。

The problem you have has nothing to do with Emojis at all. 你遇到的问题根本与Emojis无关。 Any attempt to detect Emojis in the string will fail - for the simple reason that you don't have a string in the first place, you have [NSNull null]. 任何在字符串中检测Emojis的尝试都将失败 - 原因很简单,你首先没有字符串,你有[NSNull null]。 The problem might be fixed by using objectForKey - you might get nil instead which behaves a lot more forgiving. 可以通过使用objectForKey来解决这个问题 - 你可能会得到nil而不是更宽容的行为。 Or you still get [NSNull null]. 或者你仍然得到[NSNull null]。

Find out why you are getting [NSNull null]. 找出你获得的原因[NSNull null]。 Somebody puts it there. 有人把它放在那里。 If you can't prevent it from being there, then you need to handle it. 如果你不能阻止它在那里,那么你需要处理它。

Now with the new release of iOS 10 , for the following emojis it doesn't work: 现在有了iOS 10的新版本,对于以下表情符号,它不起作用:

Emojis 表情符号

The following code snippet is tried and tested for both iOS 9 and iOS 10: 针对iOS 9和iOS 10尝试并测试了以下代码段:

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
    }
}

Create a String extension in your app as mentioned above. 如上所述,在您的应用中创建一个String扩展。

And can be used like this: 并且可以像这样使用:

if string.containsEmoji {
    // Do operations here
}

Simple Swift solution with checking every scalar in unicodeScalars are in the set CharacterSet.symbols 检查unicodeScalars中每个标量的简单Swift解决方案都在设置的CharacterSet.symbols中

extension String {
    var containsEmoji: Bool {
        for scalar in unicodeScalars {
            if CharacterSet.symbols.contains(scalar) {
                return true
            }
        }

        return false
    }
}

But I found some emoji 1.0 items like ℹ️ is not classify as an emoji. 但是我发现一些像ℹ️这样的表情符号1.0项目并没有归类为表情符号。 So I create this checker: 所以我创建了这个检查器:

extension Unicode.Scalar {
    extension Unicode.Scalar {
        var isEmojiMiscSymbol: Bool {
            switch self.value {
            case 0x2030...0x329F:   // Misc symbols
                return true
            default:
                return false
            }
        }
    }
}

And this is the checker which can detect ℹ️: 这是可以检测到ℹ️的检查器:

extension String {
    var containsEmoji: Bool {
        for scalar in unicodeScalars {
            if CharacterSet.symbols.contains(scalar) {
                return true
            } else if scalar.isEmojiMiscSymbol {
                return true
            }
        }

        return false
    }
}

As you've probably noticed, all of these emoji detecting methods break almost anytime Apple adds new emojis. 正如您可能已经注意到的那样,所有这些表情符号检测方法几乎在任何时候Apple都会添加新的表情符号。

I've created a CG scanning solution which should work for all current and all FUTURE emojis here: https://stackoverflow.com/a/14472163/2057171 我已经创建了一个CG扫描解决方案,该解决方案适用于所有当前和所有FUTURE表情符号: https//stackoverflow.com/a/14472163/2057171

To my knowledge it's the only actual answer to this issue posted anywhere online. 据我所知,这是在网上随处发布的这个问题的唯一实际答案。


-(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;

}

You can use it like so: 您可以像这样使用它:

NSString *myString = @"Hello this contains 😇 an emoji";

BOOL containsEmoji = [self isEmoji:myString];
if (containsEmoji) {
    NSLog(@"Contained Emoji");
} else {
    NSLog(@"Did not contain Emoji");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM