第一次登微信 發表於 2022-5-16 09:02:23

正则表达式中问号(?)的正确用法详解

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">1、直接跟随在子表达式后面</a></li><li><a href="#_label1">2、非贪婪匹配</a></li><li><a href="#_label2">3、非获取匹配</a></li><li><a href="#_label3">4、断言</a></li><li><a href="#_label4">参考资料:</a></li></ul></div><p>正则表达式中&ldquo;?&rdquo;的用法大概有以下几种</p>
<p class="maodian"><a name="_label0"></a></p><h2>1、直接跟随在子表达式后面</h2>
<p>这种方式是最常用的用法,具体表示匹配前面的一次或者0次,类似于{0,1},如:abc(d)?可匹配abc和abcd</p>
<p class="maodian"><a name="_label1"></a></p><h2>2、非贪婪匹配</h2>
<p>关于贪婪和非贪婪,贪婪匹配的意思是,在同一个匹配项中,尽量匹配更多所搜索的字符,非贪婪则相反。正则匹配的默认模式是贪婪模式,当?号跟在如下限制符后面时,使用非贪婪模式(*,+,?,{n},{n,},{n,m})</p>
<p>如正则表达式 \S+c 匹配字符串aaaacaaaaaaac的结果是aaaacaaaaaaac,而\S+?c则会优先匹配aaaac</p>
<p class="maodian"><a name="_label2"></a></p><h2>3、非获取匹配</h2>
<p>当我们使用正则表达式的时候,捕获的字符串会被缓存起来以供后续使用,具体表现为每个()中的表达式所匹配到的内容在进行正则匹配的过程中,都会被缓存下来,如以下代码</p>
<div class="jb51code"><pre class="brush:js;">var testReg=/(a+)(b*)c/;
testReg.test('aaaabbbccc');//输出true
console.log(RegExp.$1);//输出aaaa
console.log(RegExp.$2);//输出bbb
</pre></div>
<p>但是,如果在子分组中加入?:之后,分组依然成立,但是不会被缓存下来,看以下代码</p>
<div class="jb51code"><pre class="brush:js;">var testReg=/(a+)(?:b*)c/;
testReg.test('aaaabbbccc');//输出true
console.log(RegExp.$1);//输出aaaa
console.log(RegExp.$2);//输出""
</pre></div>
<p class="maodian"><a name="_label3"></a></p><h2>4、断言</h2>
<p>我们知道,正则表达式中大部分的结构所匹配的文本最终会出现在匹配结果中,但也有一部分结构并不真正匹配文本,而只是负责判断某个位置左/右侧是否符合要求,这种结构被称为断言</p>
<p>常用的断言有以下四种</p>
<table><tbody><tr><td><p>(?=pattern)</p></td><td><p>非获取匹配,正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。</p></td></tr><tr><td><p>(?!pattern)</p></td><td><p>非获取匹配,正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。</p></td></tr><tr><td><p>(?&lt;=pattern)</p></td><td><p>非获取匹配,反向肯定预查,与正向肯定预查类似,只是方向相反。</p></td></tr><tr><td><p>(?&lt;!patte_n)</p></td><td><p>非获取匹配,反向否定预查,与正向否定预查类似,只是方向相反。</p></td></tr></tbody></table>
<p>以下的段落中,我们将统一使用pattern表示断言的条件</p>
<p>?=pattern和?&lt;=pattern分别表示匹配断言成立时左侧和右侧的文本,只有断言成立了,左侧或右侧的文本才会被匹配,但断言所匹配的结果并不会出现在匹配结果中,具体例子可以看以下代码</p>
<div class="jb51code"><pre class="brush:js;">var testReg=/test(?=123)/;
var result=testReg.exec('test123');
console.log(result)//输出test

var result2=testReg.exec('test12');
console.log(result2)//输出null
</pre></div>
<p>我们可以看到test(?=123)可以匹配到test123中的test,但是并不能匹配test12中的test,对于?&lt;=pattern同理,可以看以下代码</p>
<div class="jb51code"><pre class="brush:js;">var testReg=/(?&lt;=123)test/;
var result=testReg.exec('123test');
console.log(result)//输出test

var result2=testReg.exec('12test');
console.log(result2)//输出null
</pre></div>
<p>同样(?=123)test可以匹配到123test中的test,匹配不到12test中的test,并且匹配结果同样不包含断言</p>
<p>对于?!pattern和?&lt;!pattern可以看成是上面两个表达式的取反,分别匹配断言不成立时的左侧和右侧文本,具体可以看以下代码</p>
<div class="jb51code"><pre class="brush:js;">var testReg=/test(?!123)/;
var result=testReg.exec('test123');
console.log(result)//输出null

var result2=testReg.exec('test12');
console.log(result)//输出test
var testReg=/(?&lt;!123)test/;
var result=testReg.exec('123test');
console.log(result)//输出null

var result2=testReg.exec('12test');
console.log(result2)//输出test
</pre></div>
<p>如上我们可以看到这个时候要匹配到左侧或者右侧的test,需要括号里的断言不成立时,才能匹配的到了</p>
<p class="maodian"><a name="_label4"></a></p><h2>参考资料:</h2>
<p><a href="https://blog.csdn.net/u014762221/article/details/68953155" rel="external nofollow"target="_blank">https://blog.csdn.net/u014762221/article/details/68953155</a></p>
<p><a href="https://www.jianshu.com/p/08c2fa742c1b" rel="external nofollow"target="_blank">https://www.jianshu.com/p/08c2fa742c1b</a></p>
頁: [1]
查看完整版本: 正则表达式中问号(?)的正确用法详解