如何处理文字中的emoji?
发布日期:2022-03-18 08:27:41 浏览次数:34 分类:技术文章

本文共 9851 字,大约阅读时间需要 32 分钟。

开源中国的”弹一弹”中处理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类,由改变而来。支持普通的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使用的是开源项目,在其基础上加了一些内容。转后的结果为:

: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在后台给处理了。如下

这里写图片描述

转载地址:https://windzen.blog.csdn.net/article/details/53609943 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:NSAttributedString
下一篇:Text Programming Guide for iOS

发表评论

最新留言

感谢大佬
[***.8.128.20]2024年04月22日 04时23分30秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

MySQL数据库从入门到实战应用(学习笔记二) 2021-06-30
种树:二叉树、二叉搜索树、AVL树、红黑树、哈夫曼树、B树、树与森林 2021-06-30
【C++】攻克哈希表(unordered_map) 2021-06-30
转:【答学员问】- 该如何根据岗位学习相关技能 2021-06-30
转:【答学员问】有什么经验教训,是你在面试很多次之后才知道的? 2021-06-30
消息队列:解耦、异步、削峰,现有MQ对比以及新手入门该如何选择MQ? 2021-06-30
【奇技淫巧】-- 三角形最小路径和 2021-06-30
【小技巧】argc和argv的用法 2021-06-30
学不下去了怎么办? 2021-06-30
二叉树的前中后序遍历(迭代法)(带动画) 2021-06-30
【小技巧】【XShell】【Xftp】Windows桌面与Linux虚拟机互传文件 2021-06-30
【redis入门】Centos下安装redis 2021-06-30
【redis入门】redis安装后相关知识串讲 2021-06-30
【redis】来吧,展示一下redis 发布-订阅模式 2021-06-30
讲通C/C++预编译/条件编译指令 #ifdef,#ifndef,#endif,#define,… 2021-06-30
【redis6.0.6】redis源码慢慢学,慢慢看 -- 第二天:空间配置(zmalloc) 2021-06-30
当下热点词再学:redis缓存预热、更新、降级,限流 2021-06-30
【redis6.0.6】redis源码慢慢学,慢慢看 -- 第五天:adlist 2021-06-30
别抖,OK? 操作系统抖动现象、网络抖动与延迟、函数抖动之防抖与节流,串讲 2021-06-30
第六天:网络处理(anet部分)-- redis源码慢慢学,慢慢看【redis6.0.6】 2021-06-30