在写聊天系统的时候,不可避免地要对聊天系统中的消息做一些解析常见的比如一句话中带有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;}
...