如何处理文字中的emoji?

来源:互联网 发布:环境保护实用数据手册 编辑:程序博客网 时间:2024/06/06 15:40

开源中国的”弹一弹”中处理emoji的过程

emoji键盘

开源中国的emoji键盘类为EmojiPageVC,继承自UIPageViewController,为分页控制器。分页控制器的每个页面上的控制器类型为EmojiPanelVC,继承自UIViewController
EmojiPanelVC使用UICollectionView来布局emoji。EmojiPanelVC还有两个block回调:

  • void (^didSelectEmoji)(NSTextAttachment *textAttachment):表示的是点击某个emoji后的回调
  • void (^deleteEmoji)():表示的是删除某个emoji的回调

这里写图片描述

UICollectionView的数据源是一个名为emoji.plist的plist文件,只使用了其中的一部分。plist转为字典,key对应的的为名称字符串,value对应的为image的名称。如下:
这里写图片描述

点击UICollectionView的某一项之后的调用的结果如下:
//选中一个emoji的图片

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{    NSInteger section = indexPath.section;    NSInteger row     = indexPath.row;    if (section == 2 && row == 6) {        //block回调,删除        _deleteEmoji();    } else {        NSInteger emojiNum = _pageIndex * 20 + section * 7 + row + 1;        NSString *emojiImageName, *emojiStr;        if (emojiNum >= 106) {//emojiNum大于等于106的图片,图片名称类似为":finnadie:"            emojiStr = Utils.emojiDict[@(emojiNum).stringValue];            //去掉":"            emojiImageName = [emojiStr stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@":"]];        } else {//emojiNum小于106的图片,图片名称类似为"084"            emojiStr = [NSString stringWithFormat:@"[%ld]", emojiNum - 1];            emojiImageName = [NSString stringWithFormat:@"%03ld", emojiNum];        }        //创建Attachment        NSTextAttachment *textAttachment = [NSTextAttachment new];        textAttachment.image = [UIImage imageNamed:emojiImageName];        [textAttachment adjustY:-3];//调整位置        //给textAttachment关联一个对象        objc_setAssociatedObject(textAttachment, @"emoji", emojiStr, OBJC_ASSOCIATION_RETAIN_NONATOMIC);        //block回调,参数为NSTextAttachment        _didSelectEmoji(textAttachment);    }}

EmojiPageVC中处理回调。例如我们输入”we”后,再输入一个emoji这里写图片描述。处理的过程如下:

        _didSelectEmoji = ^(NSTextAttachment *textAttachment) {//选择了一个emoji            //通过NSTextAttachment创建emoji属性字符串            NSAttributedString *emojiAttributedString = [NSAttributedString attributedStringWithAttachment:textAttachment];            //通过textView的attributedText创建一个新的mutableAttributeString            NSMutableAttributedString *mutableAttributeString = [[NSMutableAttributedString alloc] initWithAttributedString:textView.attributedText];            //使用emojiAttributedString来替换            [mutableAttributeString replaceCharactersInRange:textView.selectedRange withAttributedString:emojiAttributedString];            //赋值给textView的attributedText            textView.attributedText = mutableAttributeString;            textView.textColor = [UIColor titleColor];            [textView insertText:@""];            textView.font = [UIFont systemFontOfSize:16];        };

这里写图片描述

删除emoji:

        _deleteEmoji = ^ {//删除一个emoji            [textView deleteBackward];        };

上传emoji

发表一个”弹一弹”,在上传过程中如何处理emoji?
开源中国是这样处理的:

+ (NSString *)convertRichTextToRawText:(UITextView *)textView{    NSMutableString *rawText = [[NSMutableString alloc] initWithString:textView.text];    //遍历其中的attachment    [textView.attributedText enumerateAttribute:NSAttachmentAttributeName                                        inRange:NSMakeRange(0, textView.attributedText.length)                                        options:NSAttributedStringEnumerationReverse                                     usingBlock:^(NSTextAttachment *attachment, NSRange range, BOOL *stop) {                                                    if (!attachment) {return;}                                                    //存在attachment,获取关联对象,即emojiStr,可能为[x]或者":xxxx:"                                                    NSString *emojiStr = objc_getAssociatedObject(attachment, @"emoji");                                                    //出入字符串                                                    [rawText insertString:emojiStr atIndex:range.location];                                                }];    //匹配iOS系统的emoji    NSString *pattern = @"[\ue000-\uf8ff]|[\\x{1f300}-\\x{1f7ff}]|\\x{263A}\\x{FE0F}|☺";    NSError *error = nil;    NSRegularExpression *re = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:&error];    NSArray *resultsArray = [re matchesInString:textView.text options:0 range:NSMakeRange(0, textView.text.length)];    //emoji转为text的字典    NSBundle *bundle = [NSBundle mainBundle];    NSString *path = [bundle pathForResource:@"emojiToText" ofType:@"plist"];    NSDictionary *emojiToText = [[NSDictionary alloc] initWithContentsOfFile:path];    //把iOS系统的emoji替换为文字,例如":grinning::sweat_smile:"    for (NSTextCheckingResult *match in [resultsArray reverseObjectEnumerator]) {        NSString *emoji = [textView.text substringWithRange:match.range];        [rawText replaceCharactersInRange:match.range withString:emojiToText[emoji]];    }    return [rawText stringByReplacingOccurrencesOfString:@"\U0000fffc" withString:@""];}

举个例子说明,我们输入以下的内容:
这里写图片描述
前两个emoji为iOS系统的emoji,后面连个是自定义emoji键盘的。

最看是rawText的内容为:
这里写图片描述

textView.attributedText遍历其中的NSAttachmentAttributeName之后,rawText的内容为:
这里写图片描述

需要注意的是这里写图片描述,在emoji.plist文件中是这样定义的:
这里写图片描述

然后是替换,系统的emoji,之后rawText内容为:
这里写图片描述

网络获取emoji之后的显示

发表”弹一弹”之后,在cell中显示动弹。网络获取的内容为:

aa:grinning::sweat_smile:[][]

这时需要把字符串替换为emoji

+ (NSAttributedString *)emojiStringFromRawString:(NSString *)rawString{    //创建属性字符处    NSMutableAttributedString *emojiString = [[NSMutableAttributedString alloc] initWithString:rawString];    //emoji字典    NSDictionary *emoji = self.emojiDict;    //匹配emoji unicode编码[\u4e00-\u9fa5]匹配所有中文    NSString *pattern = @"\\[[a-zA-Z0-9\\u4e00-\\u9fa5]+\\]|:[a-zA-Z0-9\\u4e00-\\u9fa5_]+:";    NSError *error = nil;    NSRegularExpression *re = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:&error];    NSArray *resultsArray = [re matchesInString:rawString options:0 range:NSMakeRange(0, rawString.length)];    NSMutableArray *emojiArray = [NSMutableArray arrayWithCapacity:resultsArray.count];    for (NSTextCheckingResult *match in resultsArray) {        NSRange range = [match range];        NSString *emojiName = [rawString substringWithRange:range];        if ([emojiName hasPrefix:@"["] && emoji[emojiName]) {//自定义的emoji,带"["的            //创建attachment 添加图片            NSTextAttachment *textAttachment = [NSTextAttachment new];            textAttachment.image = [UIImage imageNamed:emoji[emojiName]];            //调整位置            [textAttachment adjustY:-3];            //创建attribute string            NSAttributedString *emojiAttributedString = [NSAttributedString attributedStringWithAttachment:textAttachment];            //创建字典,,添加到emojiArray中            [emojiArray addObject: @{@"image": emojiAttributedString, @"range": [NSValue valueWithRange:range]}];        } else if ([emojiName hasPrefix:@":"]) {//以":"开头的            if (emoji[emojiName]) {//emoji字典中存在的                [emojiArray addObject:@{@"text": emoji[emojiName], @"range": [NSValue valueWithRange:range]}];            } else {//emoji字典中不存在的                UIImage *emojiImage = [UIImage imageNamed:[emojiName stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@":"]]];                NSTextAttachment *textAttachment = [NSTextAttachment new];                textAttachment.image = emojiImage;                [textAttachment adjustY:-3];                NSAttributedString *emojiAttributedString = [NSAttributedString attributedStringWithAttachment:textAttachment];                [emojiArray addObject: @{@"image": emojiAttributedString, @"range": [NSValue valueWithRange:range]}];            }        }    }    //遍历emojiArray    for (NSInteger i = emojiArray.count -1; i >= 0; i--) {        NSRange range;        [emojiArray[i][@"range"] getValue:&range];//获取range        //替换range中的内容        if (emojiArray[i][@"image"]) {            [emojiString replaceCharactersInRange:range withAttributedString:emojiArray[i][@"image"]];        } else {            [emojiString replaceCharactersInRange:range withString:emojiArray[i][@"text"]];        }    }    return emojiString;}

处理后的结果为:
这里写图片描述

Coding iOS客户端”发冒泡”处理emoji过程

emoji键盘

Coding的emoji键盘使用的是AGEmojiKeyboardView类,由AGEmojiKeyboard改变而来。支持普通的emoji,也支持大图Monkey和Monkey_Gif(自定义的)。如下:
这里写图片描述这里写图片描述这里写图片描述

点击一个emoji之后,调用的代理方法- (void)emojiKeyBoardView:(AGEmojiKeyboardView *)emojiKeyBoardView didUseEmoji:(NSString *)emoji

- (void)emojiKeyBoardView:(AGEmojiKeyboardView *)emojiKeyBoardView didUseEmoji:(NSString *)emoji {    NSRange selectedRange = self.tweetContentView.selectedRange;    NSString *emotion_monkey = [emoji emotionMonkeyName];    if (emotion_monkey) {//monkey类emoji表情        emotion_monkey = [NSString stringWithFormat:@" :%@: ", emotion_monkey];        self.tweetContentView.text = [self.tweetContentView.text stringByReplacingCharactersInRange:selectedRange withString:emotion_monkey];        self.tweetContentView.selectedRange = NSMakeRange(selectedRange.location +emotion_monkey.length, 0);        [self textViewDidChange:self.tweetContentView];    }else{//非monkey类emoji表情        self.tweetContentView.text = [self.tweetContentView.text stringByReplacingCharactersInRange:selectedRange withString:emoji];        self.tweetContentView.selectedRange = NSMakeRange(selectedRange.location +emoji.length, 0);        [self textViewDidChange:self.tweetContentView];    }}

输入如下的emoji,这里写图片描述这里写图片描述这里写图片描述,之后,textView的文本内容是:
这里写图片描述

上传emoji

上传emoji的时候,需要把emoji转为字符。Coding使用的是开源项目NSString-Emoji,在其基础上加了一些内容。转后的结果为:

:smiley: :哈哈:  :奔月: 

基本逻辑是遍历字符串,然后替换字符串:

    [text enumerateSubstringsInRange:NSMakeRange(0, text.length) options:NSStringEnumerationByComposedCharacterSequences usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {        if (self.aliaseForEmojis[substring]) {            NSString *aliase = self.aliaseForEmojis[substring];            resultText = [resultText stringByReplacingOccurrencesOfString:substring withString:aliase];        }    }];

把字符串转为emoji

貌似的是Coding在后台给处理了。如下
这里写图片描述

0 0
原创粉丝点击