当前位置: 首页 > news >正文

解析带emoji和链接的聊天系统消息

在写聊天系统的时候,不可避免地要对聊天系统中的消息做一些解析
常见的比如一句话中带有emoji、link等信息的时候,要把emoji解析成图片、把link转成可以点击的
(项目中没有做对图片做行内处理,而是把图片像微信一样作为单独消息发送)
我们知道react的标签都是jsx的,所以在解析消息的时候,就必须在得到消息内容的时候,就先把消息内容分段截取
比如这样一则消息

今天吃饭了吗?[emoji]我还没吃呢[emoji],给你个链接看看吧!http://www.google.com/

emoji要解析成图片,http://www.google.com/ 要解析成可以点击的链接,之间的文字要解析成文本

jquery时代,只需要使用正则匹配emoji,替换成图片,用正则匹配链接,替换成a标签即可
但是在react里,这三者对应的是不同的jsx标签。所以必须把文本解析成分段式的

思路:
上面这句话,可以解析成6部分

part1: 今天吃饭了吗?
part2: [emoji]
part3: 我还没吃呢
part4: [emoji]
part5: ,给你个链接看看吧!
part6: http://www.google.com/

每部分对应使用不同的jsx标签

第一步,我们先使用正则匹配emoji和链接
分别的正则如下
(匹配链接应该有更优秀的正则)

var emojiregex = new RegExp(/\ud83c[\udf00-\udfff]|\ud83d[\udc00-\ude4f]|\ud83d[\ude80-\udeff]/g, 'g'); // 匹配emoji字符
var matchUrlRegex = new RegExp(/(https?:)\/\/([^\/]+)(\/[^\?]*)?(\?[^#]*)?(#.*)?/g,'g'); // 匹配url的正则

var emojiRegArray = text.match(emojiregex); // 匹配了所有的emoji的词
var urlRegArray = text.match(matchUrlRegex);

得到两个数组,分别是匹配到的emoji和匹配到的url

第二步,使用index()方法,获取每个emoji、url的位置、长度,并记录

    var indexEmojiArray = []; // 记录表情的位置、内容的数组
    var indexUrlArray = []; // 记录链接的位置、内容的数组
    
    var pos1 = -1, pos2 = -1;//头
    if(emojiRegArray){
        for (let i = 0; i < emojiRegArray.length; i++) {
            pos1 = text.indexOf(emojiRegArray[i], pos1 + 1);
            indexEmojiArray.push({
                type: 1, // type为1表示是表情
                pos: pos1,
                length: emojiRegArray[i].length,
                res: emojiRegArray[i],
            });
        }
    }
    if(urlRegArray){
        for (let i = 0; i < urlRegArray.length; i++) {
            pos2 = text.indexOf(urlRegArray[i], pos2 + 1);
            indexUrlArray.push({
                type: 3, // type为1表示是url
                pos: pos2,
                length: urlRegArray[i].length,
                res: urlRegArray[i],
            });
        }
    }
    

第三步,按照这些元素在消息中的位置,两个数组合并成一个数组

    // 合并两个数组
    var indexArray = []; // 以上两个数组按照pos顺序合并的数组
    if(emojiRegArray && urlRegArray){
        let point1 = 0,point2 = 0;
        while(point1 < indexEmojiArray.length || point2 < indexUrlArray.length){
            if(!indexEmojiArray[point1]){ // emoji加完了
                indexArray.push(indexUrlArray[point2]);
                point2++;                
            }else if(!indexUrlArray[point2]){// url加完了
                indexArray.push(indexEmojiArray[point1]);
                point1++;
            }else{ // 两个都没加完
                if(indexEmojiArray[point1].pos < indexUrlArray[point2].pos){
                    indexArray.push(indexEmojiArray[point1]);
                    point1++;
                }else{
                    indexArray.push(indexUrlArray[point2]);
                    point2++;
                }
            }
        }
    }else if(emojiRegArray && !urlRegArray){ // 有emoji没有url
        indexArray = indexEmojiArray;
    }else if(!emojiRegArray && urlRegArray){ // 有url没有emoji
        indexArray = indexUrlArray;
    }

第四步
现在,我们得到了一个indexArray,存储了emoji和url的位置和长度的数组
现在我们要把文本也加进去,并且,emoji替换成图片

// 这里开始把indexArray加工成contentArray
    let contentArray = [];
    let point = 0; // 记录当前指针位置
    for (let i = 0; i < indexArray.length; i++) {
        // 把这一项和上一项之间的内容push成文本
        console.log(point);
        let textContent = text.substr(point, indexArray[i].pos-point);
        console.log(textContent);
        contentArray.push({type: 0, content: textContent});
        // point += textContent.length;
        if(indexArray[i].type === 1){ // 如果这一项是emoji
            // contentArray.push({ type: 1, "resources": EMOJI_MAP[indexArray[i].res] || [] });
            contentArray.push({ type: 1, resources: indexArray[i].res || [] });
            point = indexArray[i].pos + indexArray[i].length;
        }else if(indexArray[i].type === 3){ // 如果这一项是url
            contentArray.push({ type: 3, url: indexArray[i].res});
            point = indexArray[i].pos + indexArray[i].length;
        }
    }
    // 加入末尾项。如果indexArray为空,那么末尾项就是唯一的文本项
    let lastPrevItemIndex = (indexArray[indexArray.length-1] ? indexArray[indexArray.length-1].pos+indexArray[indexArray.length-1].length : 0);
    contentArray.push({type: 0, content: text.substr(lastPrevItemIndex, text.length)});

最后得到的contentArray我们return出去。

比较难的部分在第四步,思路是,我们使用一个指针,对消息做解析,一开始指针的位置为0
开头不管如何都push一个文本对象进入contentArray中
直到遇到emoji或者url位置为止
比如遇到的是emoji,我们把emoji解析成对象push到contentArray中,然后指针加上emoji的长度
最后加上末尾。如果末尾不为文本,也添加一个空的文本对象。

完毕。

下面附上所有代码


let stringToContentArray = function (text) {


    var emojiregex = new RegExp(/\ud83c[\udf00-\udfff]|\ud83d[\udc00-\ude4f]|\ud83d[\ude80-\udeff]/g, 'g');
    var matchUrlRegex = new RegExp(/(https?:)\/\/([^\/]+)(\/[^\?]*)?(\?[^#]*)?(#.*)?/g,'g'); // 匹配url的正则
    var contentArray = [];
    if (!text) { // 没有内容
        contentArray.push({ type: 0, "content": '[无内容消息]' });
        return contentArray;
    }
    var emojiRegArray = text.match(emojiregex); // 匹配了所有的emoji的词
    var urlRegArray = text.match(matchUrlRegex);
    // console.log(text);
    console.log('emojiRegArray:',emojiRegArray);
    console.log('urlRegArray:',urlRegArray);
    if (emojiRegArray === null && urlRegArray === null) { // 没有emoji表情, 也没有链接
        contentArray.push({ type: 0, "content": text });
        return contentArray;
    }
    

    var indexEmojiArray = []; // 记录表情的位置、内容的数组
    var indexUrlArray = []; // 记录链接的位置、内容的数组
    var indexArray = []; // 以上两个数组按照pos顺序合并的数组
    var pos1 = -1, pos2 = -1;//头
    if(emojiRegArray){
        for (let i = 0; i < emojiRegArray.length; i++) {
            pos1 = text.indexOf(emojiRegArray[i], pos1 + 1);
            indexEmojiArray.push({
                type: 1, // type为1表示是表情
                pos: pos1,
                length: emojiRegArray[i].length,
                res: emojiRegArray[i],
            });
        }
    }
    if(urlRegArray){
        for (let i = 0; i < urlRegArray.length; i++) {
            pos2 = text.indexOf(urlRegArray[i], pos2 + 1);
            indexUrlArray.push({
                type: 3, // type为1表示是url
                pos: pos2,
                length: urlRegArray[i].length,
                res: urlRegArray[i],
            });
        }
    }
    if(emojiRegArray && urlRegArray){
        let point1 = 0,point2 = 0;
        while(point1 < indexEmojiArray.length || point2 < indexUrlArray.length){
            if(!indexEmojiArray[point1]){ // emoji加完了
                indexArray.push(indexUrlArray[point2]);
                point2++;                
            }else if(!indexUrlArray[point2]){// url加完了
                indexArray.push(indexEmojiArray[point1]);
                point1++;
            }else{ // 两个都没加完
                if(indexEmojiArray[point1].pos < indexUrlArray[point2].pos){
                    indexArray.push(indexEmojiArray[point1]);
                    point1++;
                }else{
                    indexArray.push(indexUrlArray[point2]);
                    point2++;
                }
            }
        }
    }else if(emojiRegArray && !urlRegArray){ // 有emoji没有url
        indexArray = indexEmojiArray;
    }else if(!emojiRegArray && urlRegArray){ // 有url没有emoji
        indexArray = indexUrlArray;
    }

    console.log("indexArray: ", indexArray);

    // 这里开始把indexArray加工成contentArray
    let point = 0; // 记录当前指针位置
    for (let i = 0; i < indexArray.length; i++) {
        // 把这一项和上一项之间的内容push成文本
        console.log(point);
        let textContent = text.substr(point, indexArray[i].pos-point);
        console.log(textContent);
        contentArray.push({type: 0, content: textContent});
        // point += textContent.length;
        if(indexArray[i].type === 1){ // 如果这一项是emoji
            // contentArray.push({ type: 1, "resources": EMOJI_MAP[indexArray[i].res] || [] });
            contentArray.push({ type: 1, resources: indexArray[i].res || [] });
            point = indexArray[i].pos + indexArray[i].length;
        }else if(indexArray[i].type === 3){ // 如果这一项是url
            contentArray.push({ type: 3, url: indexArray[i].res});
            point = indexArray[i].pos + indexArray[i].length;
        }
    }
    // 加入末尾项。如果indexArray为空,那么末尾项就是唯一的文本项
    let lastPrevItemIndex = (indexArray[indexArray.length-1] ? indexArray[indexArray.length-1].pos+indexArray[indexArray.length-1].length : 0);
    contentArray.push({type: 0, content: text.substr(lastPrevItemIndex, text.length)});
    
    return contentArray;
}

相关文章:

  • 学习内容
  • 学习Kubernetes 和容器技术体系的最佳方法
  • windows 服务安装脚本拾遗
  • 北极熊“梦龙”武汉相亲
  • SAP OTR 字段维护 更改SAP的字段翻译
  • ubuntu18.04 ssh 远程系统拒绝连接 解决方法
  • Java 中队列的使用
  • 金融壹账通将推动新一轮金融科技创新浪潮
  • 安卓布局修改基础常识篇之TextView属性
  • Javascript基础系列-表达式和运算符
  • 让nginx 的ssi支持include相对路径
  • 对超线程几个不同角度的解释
  • linux awk命令详解
  • 常用的math函数
  • Apache的基本使用
  • export和import的用法总结
  • iOS 颜色设置看我就够了
  • Netty 4.1 源代码学习:线程模型
  • Python代码面试必读 - Data Structures and Algorithms in Python
  • SpringBoot几种定时任务的实现方式
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • Unix命令
  • vue+element后台管理系统,从后端获取路由表,并正常渲染
  • Windows Containers 大冒险: 容器网络
  • 复习Javascript专题(四):js中的深浅拷贝
  • 容器化应用: 在阿里云搭建多节点 Openshift 集群
  • 深入浅出webpack学习(1)--核心概念
  • 数组大概知多少
  • 腾讯优测优分享 | Android碎片化问题小结——关于闪光灯的那些事儿
  • 移动端 h5开发相关内容总结(三)
  • 关于Kubernetes Dashboard漏洞CVE-2018-18264的修复公告
  • ​用户画像从0到100的构建思路
  • #预处理和函数的对比以及条件编译
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (zt)最盛行的警世狂言(爆笑)
  • (二)构建dubbo分布式平台-平台功能导图
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (力扣)循环队列的实现与详解(C语言)
  • (亲测成功)在centos7.5上安装kvm,通过VNC远程连接并创建多台ubuntu虚拟机(ubuntu server版本)...
  • (一)插入排序
  • (源码版)2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模
  • *1 计算机基础和操作系统基础及几大协议
  • *Django中的Ajax 纯js的书写样式1
  • .NET 4.0中使用内存映射文件实现进程通讯
  • .NET Standard、.NET Framework 、.NET Core三者的关系与区别?
  • .NET 设计模式初探
  • .Net 中的反射(动态创建类型实例) - Part.4(转自http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx)...
  • .NET/C# 异常处理:写一个空的 try 块代码,而把重要代码写到 finally 中(Constrained Execution Regions)
  • .sh文件怎么运行_创建优化的Go镜像文件以及踩过的坑
  • :如何用SQL脚本保存存储过程返回的结果集
  • @ModelAttribute使用详解
  • [Android]使用Git将项目提交到GitHub
  • [BZOJ 1040] 骑士
  • [CareerCup] 13.1 Print Last K Lines 打印最后K行
  • [CTF]2022美团CTF WEB WP