解析帶emoji和連接的聊天系統消息

在寫聊天系統的時候,不可避免地要對聊天系統中的消息作一些解析
常見的好比一句話中帶有emoji、link等信息的時候,要把emoji解析成圖片、把link轉成能夠點擊的
(項目中沒有作對圖片作行內處理,而是把圖片像微信同樣做爲單獨消息發送)
咱們知道react的標籤都是jsx的,因此在解析消息的時候,就必須在獲得消息內容的時候,就先把消息內容分段截取
好比這樣一則消息react

今天吃飯了嗎?[emoji]我還沒吃呢[emoji],給你個連接看看吧!http://www.google.com/

emoji要解析成圖片,http://www.google.com/ 要解析成能夠點擊的連接,之間的文字要解析成文本jquery

jquery時代,只須要使用正則匹配emoji,替換成圖片,用正則匹配連接,替換成a標籤便可
可是在react裏,這三者對應的是不一樣的jsx標籤。因此必須把文本解析成分段式的數組

思路:
上面這句話,能夠解析成6部分微信

part1: 今天吃飯了嗎?
part2: [emoji]
part3: 我還沒吃呢
part4: [emoji]
part5: ,給你個連接看看吧!
part6: http://www.google.com/

每部分對應使用不一樣的jsx標籤google

第一步,咱們先使用正則匹配emoji和連接
分別的正則以下
(匹配連接應該有更優秀的正則)url

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和匹配到的url3d

第二步,使用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],
            });
        }
    }

第三步,按照這些元素在消息中的位置,兩個數組合併成一個數組code

// 合併兩個數組
    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;
}
相關文章
相關標籤/搜索