emoji表情处理
iOS不倒,博客不停
好久没有更新简书了,因为新公司,真的很忙!前几天一直忙emoji,正好阳光明媚就记录一下
emoji在社交类APP很常用,比如发动态,圈子,还有回复评论,还有会话
4EFD08C4-32F7-46F1-97A5-291B19D3EF03.png在玩弄emoji 我想这位大神更牛逼:http://www.jianshu.com/p/3bfeb201794a
他介绍了emoji的历史还有emoji的原理,最后是一份非常漂亮的emoji键盘Demo
我这里记录的是一个我在开发过程比较恶心的东西:
Unicode与utf-8的转码;
后台在处理emoji的态度,直接就是不处理,所以我们需要对emoji包括中文,数字,还有特殊字符进行编码还有解码
//编码
NSString *uniStr = [NSString stringWithUTF8String:[_barrageText.text UTF8String]];
NSData *uniData = [uniStr dataUsingEncoding:NSNonLossyASCIIStringEncoding];
NSString *goodStr = [[NSString alloc] initWithData:uniData encoding:NSUTF8StringEncoding] ;
NSLog(@"---编码--->[%@]",goodStr);
//解码
const char *jsonString = [goodStr UTF8String]; // goodStr 服务器返回的 json
NSData *jsonData = [NSData dataWithBytes:jsonString length:strlen(jsonString)];
NSString *goodMsg1 = [[NSString alloc] initWithData:jsonData encoding:NSNonLossyASCIIStringEncoding];
NSLog(@"---解码--->[%@]",goodMsg1);
2017-05-15 10:16:17.858 DFRomwe[650:153981] ---编码--->[hello\ud83d\ude18\ud83d\ude18world\u4e16\u754chaha\ud83d\ude17]
2017-05-15 10:16:17.859 DFRomwe[650:153981] ---解码--->[hello😘😘world世界haha😗]
总想着事情就能这么轻松解决!!!
可是,然后,呵呵呵,你不去了解一下东西,还是不行的
果然,后台不作处理的情况下,如果返回JSON这就不行了,因为会默认带有转义字符: *** "\" *** 会导致下面这个情况:
//在这里以😀表情为例,😀的Unicode编码为U+1F604,UTF-16编码为:\ud83d\ude04
NSString * emojiUnicode = @"\U0001F604";
NSLog(@"emojiUnicode:%@",emojiUnicode);
//如果直接输入\ud83d\ude04会报错,加了转义后不会报错,但是会输出字符串\ud83d\ude04,而不是😀
NSString * emojiUTF16 = @"\\ud83d\\ude04";
NSLog(@"emojiUTF16:%@",emojiUTF16);
//转换
emojiUTF16 = [NSString stringWithCString:[emojiUTF16 cStringUsingEncoding:NSUTF8StringEncoding] encoding:NSNonLossyASCIIStringEncoding];
NSLog(@"emojiUnicode2:%@",emojiUTF16);
输出:
emojiUnicode:😄
emojiUnicode1:\ud83d\ude04
emojiUnicode2:😄
果断百度另外的方法
//解码
- (NSString *)decodeEmoji{
NSString *tepStr1 ;
if ([self containsString:@"\\u"]) {
tepStr1 = [self stringByReplacingOccurrencesOfString:@"\\u"withString:@"\U"];
}else{
tepStr1 = [self stringByReplacingOccurrencesOfString:@"\u"withString:@"\U"];
}
NSString *tepStr2 = [tepStr1 stringByReplacingOccurrencesOfString:@"""withString:@"\""];
NSString *tepStr3 = [[@""" stringByAppendingString:tepStr2]stringByAppendingString:@"""];
NSData *tepData = [tepStr3 dataUsingEncoding:NSUTF8StringEncoding];
NSString *axiba = [NSPropertyListSerialization propertyListWithData:tepData options:NSPropertyListMutableContainers format:NULL error:NULL];
return [axiba stringByReplacingOccurrencesOfString:@"\r\n"withString:@"\n"];
}
//编码
- (NSString *)encodeEmoji{
NSUInteger length = [self length];
NSMutableString *s = [NSMutableString stringWithCapacity:0];
for (int i = 0;i < length; i++){
unichar _char = [self characterAtIndex:i];
//判断是否为英文和数字
if (_char <= '9' && _char >='0'){
[s appendFormat:@"%@",[self substringWithRange:NSMakeRange(i,1)]];
}else if(_char >='a' && _char <= 'z'){
[s appendFormat:@"%@",[self substringWithRange:NSMakeRange(i,1)]];
}else if(_char >='A' && _char <= 'Z')
{
[s appendFormat:@"%@",[self substringWithRange:NSMakeRange(i,1)]];
}else{
[s appendFormat:@"\\"];
[s appendFormat:@"\\u%x",[self characterAtIndex:i]];
}
}
return s;
}
这是从JSON解码与编码,其实原理也很简单:
- A :就是把多余的转义斜杠扔掉,
- B :然后Unicode转utf-8;
- C :然后utf-8转Unicode;
这里我写了一个NSString的一个分类:#import "NSString+Emoji.h"
还添加了一些方法:
//判断是否存在emoji表情:因为emoji表情室友Unicode编码区间的
+ (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];
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 {
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;
}
//判断是否存在中文
//因为要保证之前的utf-8的数据也能显示
- (BOOL)includeChinese
{
for(int i=0; i< [self length];i++)
{
int a =[self characterAtIndex:i];
if( a >0x4e00&& a <0x9fff){
return YES;
}
}
return NO;
}
//判断是否以中文开头
- (BOOL)JudgeChineseFirst{
//是否以中文开头(unicode中文编码范围是0x4e00~0x9fa5)
int utfCode = 0;
void *buffer = &utfCode;
NSRange range = NSMakeRange(0, 1);
//判断是不是中文开头的,buffer->获取字符的字节数据 maxLength->buffer的最大长度 usedLength->实际写入的长度,不需要的话可以传递NULL encoding->字符编码常数,不同编码方式转换后的字节长是不一样的,这里我用了UTF16 Little-Endian,maxLength为2字节,如果使用Unicode,则需要4字节 options->编码转换的选项,有两个值,分别是NSStringEncodingConversionAllowLossy和NSStringEncodingConversionExternalRepresentation range->获取的字符串中的字符范围,这里设置的第一个字符 remainingRange->建议获取的范围,可以传递NULL
BOOL b = [self getBytes:buffer maxLength:2 usedLength:NULL encoding:NSUTF16LittleEndianStringEncoding options:NSStringEncodingConversionExternalRepresentation range:range remainingRange:NULL];
if (b && (utfCode >= 0x4e00 && utfCode <= 0x9fa5))
return YES;
else
return NO;
}