原生JS利用正则动态匹配标签,将一个特别长的html文本切割为不固定长度的字符串数组,并确保切割的时候不破坏匹配到的内容的完整性

后台的需求是这样的:

在线 html 编辑器编辑出来的文章,需要调用第三方服务做一些处理,只处理内容,不处理标签,第三方服务还限制字数,这里以 5000 为例,而如果文章里面有 html 标签,第三方服务暂时没那么智能,做的处理就会出错,而且处理过后还不能打乱之前文章的 html 结构顺序等,

后台用的 PHP,但是我就想用 JS 处理一下,试试嘛,一个人一个想法

初始方案:一开始是直接用正则处理,将文章内容用标签分成数组,然后遍历,不断的请求第三方服务接口,然后再将处理之后的结果和提取出来的标签拼接一下,是能实现,但是如果文章内容不多,段落多,得请求很多次第三方的接口,造成了一个问题,等待的时间超长…时间是累加的 不长就有了鬼了 …

修改之后:将正则提取出来记录起来,原文位置放个特殊字符标记(不影响第三方处理的标记),处理完再将标记对应的位置替换回来,至少这样能减少调用第三方服务接口的次数,减少请求累计时间,如果没有字符长度限制的话这个方案简直太棒了,但是有一个字符长度限制,这里是 5000 ,没辙,还得切割一下,但是切割还不能按照固定的长度 5000 来切割,万一 5000 刚好到了你的特殊标记的中间位置,特殊标记被打乱了,影响了处理结果,影响了你的替换,得不偿失

let str = `

杭州失踪女子大女儿发文:怀疑妈妈被人绑架

新浪新闻 今天

近日,杭州一名53岁女子离奇失踪的消息引发社会关注。

***** other ***** ***** other ***** ***** other *****
`
; // 要处理的文章,需替换成自己的文章内容,这个直接使用会报错的 let regExpStr = new RegExp('\s*<\/?.*?>\s*', 'igm'); // 匹配所有标签 let tmpObj = {}; //记录替换掉的标签 let prefix = '***&&&___' //前缀 let suffix = '___&&&***' //后缀 let result = str.replace(regExpStr, (match, offset) => { // 将标签特换成特定标记 tmpObj[offset] = match; // 记录所匹配到的标签,至于为什么不用数组而用对象,不说了,自己想 return prefix + offset + suffix; //前缀 + 偏移量 + 后缀 }) // 特定标记的正则 let fixRegExp = new RegExp('\\*{3}&{3}_{3}(\\d+)_{3}&{3}\\*{3}', 'igm'); // 特定标记的正则 let tmpArr = deal(result,fixRegExp,5000) // 获取切割之后的内容组成的数组,deal 函数见下方 /* 这里拿着 tmpArr 去第三方处理 */ tmpArr.map(el=>{ /* 后台的东西,这边就做个假设就行了,不做实际操作 */ }) /* 假设这里已经处理好了,tmpArr 是处理之后的内容组成的数组 */ result = tmpArr.join(''); // 先重新将 tmpArr 变成字符串 let res = result.replace(fixRegExp,(match,p1,offset)=>{ // 翻译之后再将特定标记再替换回来 return tmpObj[p1]; // 直接将之前保存的标签直接放回去 }) console.log(res); // 这就是第三方服务处理之后的文章
// 处理长度超出 dealNum 的字符串,dealStr: 要处理的字符串,dealReg: 匹配的正则,dealNum: 多长截取一次,默认5000
function deal(dealStr,dealReg,dealNum = 5000){
	
	let arr = []; //定义一个数组,保存截取出来的数据
	
	//定义一个递归函数,循环处理 str: 要处理的字符串,reg: 处理用到的正则,num: 处理出来的长度
	function recursion(str,reg,num){
		let s = ''; // 处理出来的字符串临时变量
		let e = ''; // 剩余需要处理的字符串
		let index = 0; // 保存距离 num 最近的匹配到的下标,保证最大限度的截取字符串并不破坏 reg 匹配到内容的完整性
		let flag = false; // 状态控制,控制是否继续往下匹配,如果匹配到的下标大于 num 没必要赋值给index,也没必要继续匹配,可以跳出去执行新的一轮
		// 用的 while do 
		while(exObj = reg.exec(str)){
			if(exObj.index < num){ //判断条件,来控制要截取到哪儿
				index = exObj.index; //不断的将最新下标赋值给 index ,以保证 index 永远是最接近 num 的下标
			}else{
				flag = true; // 超出 num 了,需要执行下一轮
				continue; //  跳出
			}
		}
		s = str.substring(0,index); // 将当前最接近 num 的字符串长度截取出来并保存 arr 里面
		arr.push(s);
		if(flag){ // 需要执行下一轮
			e = str.substring(index); // 拿到没有处理的字符,传递给下一轮
			recursion(e,reg,num); // 递归
		}
	}
	recursion(dealStr,dealReg,dealNum) // 调用递归
	return arr; // 将处理之后的字符串数组返回出去
}

由于没做第三方服务的实际操作,这里就不张贴演示截图了,程序是运行过的,没任何问题
只记录一下处理过程

你可能感兴趣的:(js)