一文精通正则表达式中的前后查找断言
<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">背景简介</a></li><li><a href="#_label1">前后查找断言概览</a></li><li><a href="#_label2">示例解析</a></li><ul class="second_class_ul"><li><a href="#_lab2_2_0">正向前瞻</a></li><li><a href="#_lab2_2_1">负向前瞻</a></li><li><a href="#_lab2_2_2">使用注意事项</a></li><li><a href="#_lab2_2_3">实际应用</a></li><ul class="third_class_ul"><li><a href="#_label3_2_3_0">匹配不以特定字符串开头的字符串</a></li><li><a href="#_label3_2_3_1">跳过带注释的行</a></li><li><a href="#_label3_2_3_2">智能引号转换</a></li></ul></ul><li><a href="#_label3">总结与启发</a></li><ul class="second_class_ul"></ul></ul></div><p class="maodian"><a name="_label0"></a></p><h2>背景简介</h2><p>在处理文本和数据时,正则表达式是不可或缺的工具之一。特别是在需要进行复杂的字符串匹配时,前后查找断言(lookaround assertions)为我们提供了额外的能力。在本章中,我们将通过一系列示例深入了解正则表达式的前后查找断言,探索它们如何在不捕获匹配文本的情况下,对匹配前后的内容做出断言。</p>
<p class="maodian"><a name="_label1"></a></p><h2>前后查找断言概览</h2>
<p>前后查找断言分为前瞻和后顾两大类,每类又包括正向和负向两种类型:</p>
<ul><li><strong>正向前瞻(Positive Lookahead) </strong> :确保所匹配的内容后面跟着指定的模式。</li><li><strong>负向前瞻(Negative Lookahead) </strong> :确保所匹配的内容后面不跟着指定的模式。</li><li><strong>正向后顾(Positive Lookbehind) </strong> :确保所匹配的内容前面跟着指定的模式。</li><li><strong>负向后顾(Negative Lookbehind) </strong> :确保所匹配的内容前面不跟着指定的模式。</li></ul>
<p class="maodian"><a name="_label2"></a></p><h2>示例解析</h2>
<p class="maodian"><a name="_lab2_2_0"></a></p><h3>正向前瞻</h3>
<div class="jb51code"><pre class="brush:js;">> 'how "are" "you" doing'.match(/(?<=")+(?=")/g)
[ 'are', 'you' ]
</pre></div>
<p>在上述代码中,我们使用了正向前瞻断言来提取被双引号包围的单词。</p>
<p class="maodian"><a name="_lab2_2_1"></a></p><h3>负向前瞻</h3>
<div class="jb51code"><pre class="brush:js;">> 'how "are" "you" doing'.match(/(?<!")+(?!")/g)
[ 'how', 'doing' ]
</pre></div>
<p>而负向前瞻断言则帮助我们提取未被双引号包围的单词。</p>
<p class="maodian"><a name="_lab2_2_2"></a></p><h3>使用注意事项</h3>
<ul><li><strong>性能考量 </strong> :前后查找断言在处理大型文本时可能会影响性能,尤其是当模式匹配长字符串时。</li><li><strong>引擎兼容性 </strong> :不同JavaScript引擎对前后查找断言的支持程度不一,特别是在正向后顾断言上。</li><li><strong>解析替代方案 </strong> :有时使用适当的解析而非正则表达式可能是更好的选择。</li></ul>
<p class="maodian"><a name="_lab2_2_3"></a></p><h3>实际应用</h3>
<p class="maodian"><a name="_label3_2_3_0"></a></p><h4>匹配不以特定字符串开头的字符串</h4>
<div class="jb51code"><pre class="brush:js;">> /^(?!abc).*$/.exec('xyz')
{ 0: 'xyz', index: 0, input: 'xyz', groups: undefined }
</pre></div>
<p>通过这个例子,我们可以看到如何使用正则表达式匹配不以'abc'开头的字符串。</p>
<p class="maodian"><a name="_label3_2_3_1"></a></p><h4>跳过带注释的行</h4>
<div class="jb51code"><pre class="brush:js;">const RE_SETTING = /^(?!#)([^:]*):(.*)$/;
</pre></div>
<p>在解析配置文件时,此正则表达式可帮助我们跳过注释行,只匹配设置行。</p>
<p class="maodian"><a name="_label3_2_3_2"></a></p><h4>智能引号转换</h4>
<div class="jb51code"><pre class="brush:js;">> const regExp = /(?<!\\)"(.*?)(?<!\\)"/g;
> String.raw`"straight" and "curly"`.replace(regExp, '“$1”')
'\\\\"straight\\" and “curly”'
</pre></div>
<p>这个例子展示了如何将直引号转换为智能引号,并处理了通过反斜杠进行转义的情况。</p>
<p class="maodian"><a name="_label3"></a></p><h2>总结与启发</h2>
<p>前后查找断言是正则表达式中的高级特性,它们极大地增强了匹配能力,允许我们仅根据匹配的前后文来确定匹配的合法性。在学习和使用这些断言时,需要考虑到性能、兼容性以及是否适合当前任务。同时,它们也提醒我们,即使在编程语言中,也有许多功能和技巧,需要我们不断探索和实践才能掌握。</p>
<p>阅读本章内容后,我意识到了正则表达式不仅仅是一个简单的字符串匹配工具,而是一个在适当使用时可以大幅提高工作效率的强大工具。在实际应用中,我们应该根据具体场景选择最合适的工具,既包括正则表达式,也包括其他解析技术,以达到最优的解决方案。</p> 太棒了!终于有人把前后查找讲这么清楚了!
之前一直对(?=)和(?!)这些符号头疼,看了很多教程都是一笔带过,越看越糊涂。今天看了楼主的帖子,终于搞明白正向前瞻和负向前瞻的区别了!
几个感受:
[*]示例很实用 - 那个提取引号内单词的例子特别直观,一眼就看出前瞻断言的作用
[*]分类清晰 - 把四种类型分门别类讲解,比零散学习效果好太多
[*]注意事项很贴心 - 特别是提到JavaScript引擎兼容性问题,这个坑我之前踩过
补充一点我的使用经验:
之前在处理配置文件时,用楼主的思路写了这样的正则:
const RE_COMMENT = /^\s*(?!#|\/\/).*$/;
用来过滤注释行,效果不错。看来前后查找真的很有用!
期待楼主出更多正则教程!这种深入浅出的技术贴比那些水文有价值多了strong
頁:
[1]