他叫钊哥 發表於 2023-12-27 09:42:22

正则表达式匹配ip地址超级详细讲解

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">一、正则匹配基本知识及概念</a></li><li><a href="#_label1">二、ip地址匹配</a></li><li><a href="#_label2">总结</a></li></ul></div><p class="maodian"><a name="_label0"></a></p><h2>一、正则匹配基本知识及概念</h2>
<p>在练习之前,需要大家知道一些基本知识,如果有一定基础的可以跳过该步骤,直接往下看。</p>
<p>正则表达式-字符类</p>
<blockquote><p>:代表a或者b,或者c字符中的一个。<br />[^abc]:代表除a,b,c以外的任何字符。<br />:代表a-z的所有小写字符中的一个。<br />:代表A-Z的所有大写字符中的一个。<br />:代表0-9之间的某一个数字字符。<br />:代表a-z或者A-Z或者0-9之间的任意一个字符。<br />:a 到 d 或 m 到 p之间的任意一个字符。</p></blockquote>
<p>正则表达式-逻辑运算符</p>
<blockquote><p>&amp;&amp;:并且<br />| :或者(可以省略)</p></blockquote>
<p>正则表达式-预定义字符</p>
<blockquote><p>&ldquo;.&rdquo; : 匹配任何字符。<br />&ldquo;\d&rdquo;:任何数字的简写;<br />&ldquo;\D&rdquo;:任何非数字[^0-9]的简写;<br />&ldquo;\s&rdquo;: 空白字符:[ \t\n\x0B\f\r] 的简写<br />&ldquo;\S&rdquo;: 非空白字符:[^\s] 的简写<br />&ldquo;\w&rdquo;:单词字符:的简写<br />&ldquo;\W&rdquo;:非单词字符:[^\w]</p></blockquote>
<p>正则表达式-数量词</p>
<blockquote><p>x? : 0次或1次<br />x* : 0次到多次<br />x+ : 1次或多次<br />X{n} : 恰好n次<br />X{n,} : 至少n次<br />X{n,m}: n到m次(n和m都是包含的,最少n次,最多m次。</p></blockquote>
<p class="maodian"><a name="_label1"></a></p><h2>二、ip地址匹配</h2>
<p><strong>题目要求:使用正则表达式匹配192.11.23.69</strong></p>
<p>须知:ip地址的范围为0.0.0.0-255.255.255.255</p>
<p>接下来我们直接进入正题吧!在我们看到题目的第一眼,大家可能觉得很简单,这不就用<code>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}</code></p>
<p style="text-align:center"><img alt="zh" src="https://img.jbzj.com/file_images/article/202312/202312270932361.png" /></p>
<p>这里我们可以看到使用上述表达式的确匹配成功。</p>
<p>虽然完成了我们的题目要求,有些细心的伙伴会发现,用红色标注出来的部分,重复了三遍,是不是我们可以用<strong>分组</strong>的方式来简化表达式并完成题目要求。我们把上面的匹配表达式换成分组之后的样子,即<code>(\d{1,3}\.){3}\d{1,3}</code></p>
<p>表达式讲解:<code>(\d{1,3}\.) </code>匹配我们前三段的ip地址和&rsquo;.&lsquo;,因为第四段ip地址最后面不能有&rsquo;.&#39;,如果我们使用在同一个分组去匹配就会出现错误情况,而\d{1,3}刚好匹配我们最后一段ip地址</p>
<p>匹配效果如下:</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202312/202312270932362.png" /></p>
<p>匹配同样成功,该模式有什么不对的地方吗?从语法上看,完全正确,也达到了我们的题目要求,可是我们有没有注意到,我们日常生活中所用的ip地址每一位都是在0-255之间,但是我们上面写的表达式会匹配0-999之间的所有ip地址,如果在未来的工作中,有这样的需求,要匹配所有合法的ip地址,那么我们上面所写的正则表达式是不是就不符合要求了,这里就需要我们使用子表达式的嵌套(注意:有一点很重要。通过上面的例子,我们发现,写一个能够匹配预期内容的正则表达式其实并不难,但是写一个能够考虑到所有可能场景,确保将不需要匹配的内容排除在外的正则表达式就困难多了)</p>
<p>所以我将上面的表达式又改进了一下(这里用到了子表达式的嵌套,如果不懂的小伙伴可以先看一下基本概念再来看接下来的内容)。我们发现当ip地址仅有一位或者两位的时候(即1.1.1.1 or 11.11.11.11),用(\d{1,2}\.)就可以完成匹配,当ip地址为三位的时候,会有这么两种情况(这里留下个疑问,考虑到初学者可能犯错的情况)?<br />1:ip地址开头为1的时候,我们后面的两位每一位的范围都在0-9之间,而\d这个元字符刚好满足了我们的要求,所以使用(1\d{2}.)就满足了我们在100-199ip地址的匹配,这个其实还相对简单,接下来就是200-255之间ip地址的匹配了,有些同学可能会想,我们可以使用匹配100-199的表达式来实现对200-255ip地址的匹配,即(2\d{2}\.)这样的表达式来实现,可是这样会把256-299之间的ip地址匹配到,违反了我们的意愿,所以我改良了一下表达式(2{2}\.]),这样就只会匹配到200-255之间的ip地址,既然子表达式都写好了,就让我们来实践看看效果吧!</p>
<p>表达式为:<code>((1\d{2}.)|(2{2}.)|(\d{1,2}.)){3}((\d{1,2})|(1\d{2})|(2{2})))</code>,伙伴们可以一起实践一下!</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202312/202312270932363.png" /></p>
<p>匹配成功,可是再写出这个表达式,我们要测试某些特殊情况是否不在我们的匹配范围内,于是我发现了以下两个比较重要的问题。</p>
<p>第一种:</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202312/202312270932364.png" /></p>
<p>合法ip地址匹配错误</p>
<p>第二种:</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202312/202312270932365.png" /></p>
<p>非法ip地址匹配成功</p>
<p>为什么会出现上面的情况?</p>
<p>当我们觉得表达式很完美的时候,虽然256超出匹配范围,但是因为(\d{1,2}\.)的影响,使得我们的非法表达式也匹配成功,本来192.11.23.200为合法表达式,却只匹配到了98.11.23.200,请大家看我用红色箭头标注的地方,会不会跟我们子表达式的顺序有关呢?那好,我来改变一下顺序,我们将(\d{1,2}\.)放到了最后,防止出现错误匹配<br />改变匹配顺序后的表达式为:</p>
<blockquote><p>( ( (2{2}.)|(1\d{2}.)|(\d{1,2}.)){3}((1\d{2})|(2{2})|(\d{1,2}))<strong>)</strong></p></blockquote>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202312/202312270932366.png" /></p>
<p>果然,第一种情况我们是因为子表达式顺序的原因,导致匹配错误。</p>
<p>可是第二种情况使用改变顺序的表达式,依然会出现以上问题(这里也就印证了上文提到的那些话,要想写出一个符合规范的表达式就很困难)。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202312/202312270932367.png" /></p>
<p>于是这里的^就起到了作用,我们可以把第一个子表达式单另拉出来加上^表示第一段ip地址开头为(\d{1,2}),这样刚好避免了我们如上的情况,效果如下:</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202312/202312270932378.png" /></p>
<p>可以看到非法ip不在我们的匹配当中。</p>
<p>其实写到这里大家是不是感觉已经大功告成了?回答:No</p>
<p>(2{2})这个表达式能否匹配239这个ip呢?不知道有没有细心的小伙伴发现</p>
<p><strong>所以最终正确的表达式应该为:</strong></p>
<blockquote><p>(^((2\d.)|(25.)|(1\d{2}.)|(\d{1,2}.))((2{2}.)|(1\d{2}.)|(\d{1,2}.){2})((1\d{2})|(2{2})|(\d{1,2})))</p></blockquote>
<p>在这里可以跟大家说一下,是否可以使用$来避免我们上述第一种问题,有兴趣的可以尝试一下,到这里,我们这道题目也算基本符合规范的完成了</p>
<p class="maodian"><a name="_label2"></a></p><h2>总结</h2>
頁: [1]
查看完整版本: 正则表达式匹配ip地址超级详细讲解