或者"$n"来对其引用:
1 var str = 'Hello, Hi, I am Hilary.';
2 var reg = /H(?!i)/g;
3 var newStr = str.replace(reg, "T$1");
4 console.log(newStr);//T$1ello, Hi, I am Hilary.
注意其中输出的语句,前面我们可以看到,如果引用符没有匹配到指定的字符,那么就会显示空串"",可是这里是直接显示了整个引用符"$1"。这是因为前瞻表达式根本就没有捕获,没有捕获也就没有引用。
非捕获性是前瞻的一个基本特征,前瞻的另外一个特性是不吃字符,意思就是前瞻的作用只是为了匹配满足前瞻表达式的字符,而不匹配前瞻本身。也就是说前瞻不会修改匹配位置,这么说我自己都觉得晦涩,我们还是来看看代码吧︽⊙_⊙︽:
1 var str = 'Hello, Hi, I am Handsome Hilary.';
2 var reg = /H(?!i)e/g;
3 var newStr = str.replace(reg, "T");
4 console.log(newStr);//Tllo, Hi, I am Handsome Hilary.
注意观察输出的字符串,前瞻的作用仅仅是匹配出满足前瞻条件的字符"H",匹配出了"Hello"和"Handsome"当中的H,但同时前瞻不会吃字符,也就是不会改变位置,接下来还是会紧接着"H"开始继续往下匹配,这时候匹配条件是"e",于是"Hello"中的"He"就匹配成功了,而"Handsome"中的"Ha"则匹配失败。
1. /H(?!i)/g --> Hello, Hi, I am Handsome Hilary.
2. /H(?!i)e/g --> Hello, Hi, I am Handsome Hilary.
四、用前瞻实现标签过滤
既然前瞻是非捕获性的,而且还不吃字符,那么了解到这些特征后我们现在终于可以完成我们的需求了吧?因为它不吃字符,所以具体的标签字符还得由我们自己来吃:
1 var str = '<div>,<p>,<h1>,<span>,</span>,</h1>,</p>,</div>';
2 var reg = /<(\/?)(?!p|\/p).*?>/g;
3 var newStr = str.replace(reg, "<$1p>");
4 console.log(newStr);//<p>,<p>,<p>,<p>,</p>,</p>,</p>,</p>
聊了这么半天,终于解决了咱们的第一个需求,注意当中的".*?",虽然这里匹配的是任意字符,但是别忘了,有了前面的负向前瞻,我们匹配到的都是后面不会紧跟着"p"或者"/p"的字符"<"。
/<(?!p|\/p)/g --> <div>,<p>,<h1>,<span>,</span>,</h1>,</p>,</div>
注意在这里用了一个管道符"|"来匹配"\/p",虽然前面已经有了"(\/?)"匹配结束符,但是切记这里的分组选项不能省略,因为这里的量词是可以出现0次。我们来试想一下如果用"/<(\/?)(?!p).*?>/g"来匹配"</p>"这个标签,当量次匹配到"/"的时候,发现可以匹配,便记录下来,然后对"/"进行前瞻判断,但是后面却接着一个"p"于是不能匹配,丢掉;注意这时"(\/?)"的匹配字符是0个,于是乎转而对"<"进行前瞻判断,这里的"<"后面紧接着的是"/p"而不是"p",于是乎成功匹配,所以这个标签会被替换掉;而且,由于之前的分组匹配到的字符是0个,也就是没有匹配到字符,所以后面的引用是个空串。
1 var str = '<div>,<p>,<h1>,<span>,</span>,</h1>,</p>,</div>';
2 var reg = /<(\/?)(?!p).*?>/g;
3 var newStr = str.replace(reg, "<$1p>");
4 console.log(newStr);//<p>,<p>,<p>,<p>,</p>,</p>,<p>,</p>
完成了第一个过滤需求,那么第二个过滤需求也就自然而然的完成了,这时候,就算有那么五六个标签需要保留,咱们也不用怕了:
1 var str = '<div>,<p>,<h1>,<span>,</span>,</h1>,</p>,</div>';
2 var reg = /<(\/?)(?!p|\/p|div|\/div).*?>/g;
3 var newStr = str.replace(reg, "<$1p>");
4 console.log(newStr);//<div>,<p>,<p>,<p>,</p>,</p>,</p>,</div>
总结
JS 的正向前瞻只是正则表达式当中一部分,没相当就这么一部分还有着这么多的奥妙呢。
在使用正向前瞻,我们需要注意的是:
- 前瞻是非捕获性的:其特征是无法引用。
- 前瞻不消耗字符:前瞻只匹配满足前瞻表达式的字符,而不匹配其本身。
话说,咱们的需求就到这了吗?真的就完了吗?同学们觉得过瘾不?有些同学觉得可能差不多了,需要消化一段时间,但是绝对有那么一部分同学还完全没过瘾呢,没关系,最后留给大家一道思考题,截止到我写这篇博客为止,我还没有想出一个解决办法呢(? ?_?)?。
需求如下:当你收到一串HTML代码,需要对这一串HTML代码过滤,将里面所有的非<p>或者<div>