听到正则表达式,大家一定不会陌生。工作项目中也经常使用正则表达式来校验文本的是否匹配规则。通常都会直接上网找寻各种格式输入的正则匹配式。比如电话/邮件等等。
除了匹配规则外,正则表达式也经常用来截取字符串,使用正则表达式也有格外的快感~
问题
下面记录一个例子
将"/test/info?page={page}&limit={limit}"这段地址中的大括号中的page和limit替换成字典中的数值。
看到这个case
,实际上,二话不说,脑中立马生成了第一个方案
方案1
无脑干.jpg看到这个例子,很快回去写一个String
的处理表达式,来将其进行转换。如下
const targetUrl = '/test/info?page={page}&limit={limit}'
const params = {
page: 1,
limit: 10
}
const replace1 = (url, params) => {
let firstIndex = url.indexOf('?');
let resultUrl=url;
if (firstIndex != -1) {
//先取到后面一段
let result = url.slice(firstIndex + 1);
let items = result.split('&');
items.forEach(item => {
let dic = item.split('=');
let key=dic[0];
resultUrl=resultUrl.replace('{'+key+'}',params[key]);
});
}
return resultUrl
}
运行这段代码,最后得到了/test/info?page=1&limit=10
。
这样的代码,很实际。只要经过自己的逻辑判断,就可以完成,但是这样的代码真是又长又臭。对字符串经过一系列的切割和替换,最后替换成了我们需要的url。
下面来看看正则表达式的方法
方案2
观察发现,其实我们的需求就是匹配得到被{}
的文本,将其替换成我们的参数。
那我们的正则匹配式,就是需要以{
开头,以}
结尾的匹配字段。
好。
先通过我们的思路,先来一个正则
const regex0=(url,params)=>{
let resultUrl = url;
//就是{}开头结尾来得到数值
let regex=/\{\w+\}/g
let matter=url.match(regex);
console.log(matter);
if(matter && matter.length){
matter.forEach(item=>{
//这里我们知道,我们得到的是包含有{}的字符串.需要将这个符号去掉
let temp = item.slice(1,item.length-1);
console.log(temp);
resultUrl= resultUrl.replace(item,params[temp]);
})
}
return resultUrl;
}
上面的正则表达式的写法,是不是就优雅了一些呢?
但是我们还是对字符串进行了剪切。作为强迫症的我们,怎么可以又对其进行剪切呢。宁愿拼接也不愿意剪切。哼~
加上条件原则,再来一个正则
const regex2=(url,params)=>{
let resultUrl = url;
//以{开头,匹配结果在{之后,以}结尾,匹配结果在}之前
let regex=/(?<=\{)\w+(?=\})/g
let matter=url.match(regex);
console.log(matter);
if(matter && matter.length){
matter.forEach(item=>{
//这里得到的item,就是去掉{}之后的值
console.log('item='+item);
resultUrl= resultUrl.replace('{'+item+'}',params[item]);
})
}
return resultUrl;
}
上面这个正则就有趣多了。通过(?=exp)
和(?<=exp)
这两个表达式,将匹配规则中不需要匹配的部分给去掉了。这样我们操作起来,看起来就优雅了好多~~~
方案3
还有第三个方案?!
what.gif强迫症的我们发现,我用来两组(?=exp)
这样的表达式才完成去头去尾的任务。然而!!发现这组正则匹配的规则可以是
const regex3=(url,params)=>{
let resultUrl = url;
//匹配规则更改成不以{开头,用}结尾的字符串
let regex=/[^{]\w+(?=\})/g
let matter=url.match(regex);
console.log(matter);
if(matter && matter.length){
matter.forEach(item=>{
console.log('item='+item);
resultUrl= resultUrl.replace('{'+item+'}',params[item]);
})
}
return resultUrl;
}
这样的匹配规则似乎更合理。
一瞬间感觉真是充满趣味性的解。看待一个问题,我们从正面(以{
开头)和反面(不以{
为开头)似乎都能得到我们想要匹配的结果~!
问题2
经过上面一段之后,对笔者来说,像是开启了一扇新世界的大门。从来只是简单的来匹配文本的正则,从文本中窃取文本的这种事从来都是用字符串来回的截取和操作才完成固定的文本获取的笔者如获至宝。
那我们赶紧就上第二个例子吧。
需求:要从下面这个抓到的html文本中获取浏览数(包含<em>/12<td>
)为9的发帖的用户id(tid
)是多少?
正常的处理问题的逻辑:观察目标文本。将上面的需求,就是需要截取一段文本,其中包含的<em>/12<td>
这段文本,然后取出其中的tid
字段。
方案1
同样,面对这样一个html
结构的文本。第一个在我脑子出现的方案就是将其解析成dom模型。然后来对对应的节点和属性进行判断。
大概思路就是 找到td
中的tr
,并且该td
中的tr
包含着<em>/12<em>
的内容。然后取出tid
的属性。
这样的方案,就是按照结构性的数据的思路,来获取。
听到这种解题方案就觉得麻烦,需要生产dom模型,然后遍历选择。
这个方案只能说差评了~
优雅方案
OK。优雅方案大家一定想到了吧。咱们肯定得用正则来做呀。
好。那我们将我们的需求用正则的思路翻译一下:
观察得到,其实就是获取<em>/12<td>
结尾,tid
开头的字符串。同时只捕获tid=
字段后面跟着的数据。
const targetText= '....'//很长很长的文本
//利用我们的(?=exp)等表达式,进行捕获.
const regex= /(?<=tid\=)\d+(?=[\s\S]*?\<\/em\>\/12\<\/td\>)/g;
最后就能直接匹配到我们想到的 tid
数字了~
帅吧~ 撒花~
cheer.gif总结
-
正则匹配式不仅能够做文本的匹配,还能进行文本的截取~(废话!)合理的使用正则,能够大幅度的提高工作的效果
-
有些问题,而且从相反的角度来想,会发现另一个天堂
网友评论