iOS开发-判断Emoji

好像好久没有写blog了,前几天服务端同学说,传入emoji给他们可能会造成一些麻烦。所以准备把emoji过滤掉。

emoji

大家应该都知道emoji是啥吧??

知道的同学可以直接跳过这段废话了。
介绍emoji之前先介绍一下emoji到底是什么组成的。

字符集和字符集编码

因为计算机中所有的信息最终都是以二进制的形式存储,我们所有的自然语言输入到计算机中之后都会被转换为计算机能够识别的二进制数据,当计算机需要显示自然语言的时候也都是把二进制数据转换为我们能够看懂的自然语言。

那么自然语言中的每个字或者每个标点就可以称为是一个字符。这些字符的集合就是字符集

字符集包含了各种各样不同的字符,但是计算机想要识别字符就需要根据一套规则进行转换,这个规则就是字符集编码。规定字符编码必须遵循两个规则:

  • 规定一个字符集中的字符由多少个字节表示
  • 制定该字符集的字符编码表,也就是该字符集中每个字符对应的二进制值

ASCII码

ASCII(American Standard Code for Information Interchange),是一种字符编码标准,它的字符集为英文字符集,它规定了字符集中的每一个字节表示,指定了字符表编码表,成为ASCII码表。已经被国际化组织定义为国际标准,成为ISO646标准。

ASCII码一共规定了128个字符的编码,比如空格”SPACE”是32(二进制00100000),大写字符A是65(二进制01000001),这128个符号只占用了一个字节后面的7位,最前面第1位规定为0。

但是由于标准ASCII字符集字符数目有限,在实际应用中往往无法满足要求,因此,国际标准化组织又制定了ISO 2022标准,它规定了在保持ISO646兼容的前提下将ASCII字符集扩充为8位的统一方法。

Unicode

但是世界上的语言不只有英语这么少的字符,很多语言如中文,韩文,日文等都有很大量的字符需要被存储,显然简单的字符表已经不够用了。

所以,人们意识到需要一种标准的规范来展示世界上的所有字符,于是Unicode就诞生了。Unicode最初是一个字符集,后面慢慢变化成了一个广义的标准,即UTF-8,UTF-16,UTF-32等等…

Emoji

Emoji字符就是Unicode字符集中的一部分,特定形象的Emoji表情符号对应着特定的Unicode字节,常见的Emoji表情符号在字符集中的范围和映射关系可以通过这个来查看 Emoji unicode characters for use on the web

判断

知道了Emoji的大概情况之后,我们可以看到在某一范围内的字符都是属于Emoji表情的。所以通常来说通过范围来判断就可以屏蔽掉一大部分的Emoji

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//判断是否存在emoji
+(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;
}

但是跑起来之后可以看到,有些Emoji还是判断不出来,其实因为Emoji是一直在更新的,写死了范围在代码里,没当emoji更新了之后,新的emoji有可能不在范围内,就会导致无法判断出来。

所以我们通过转换成UTF8的字节长度来判断,大于等于4的长度就默认为是Emoji。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//判断是否存在emoji
+(BOOL)stringContainsEmoji:(NSString *)string
{
NSUInteger stringUtf8Length = [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
if(stringUtf8Length >= 4 && (stringUtf8Length / string.length != 3))
{
return YES;
}
else
{
return NO;
}
}

这样就会稍微好一点,但是不知道会不会造成一些其他问题,如果大神们有什么更好的解决办法欢迎留言告诉我。

参考文档

深入理解Emoji(一) —— 字符集,字符集编码 - 简书

Emoji unicode characters for use on the web

深入理解Emoji(三) —— Emoji详解 - 掘金