正则表达式实践篇

hncw5523 8年前
   <ol>     <li>与搜索字符串开始处的 3 个数字匹配: /^\d{3}/ 。</li>     <li>与除 a、b 和 c 以外的任何字符匹配: /[^abc]/ 。</li>     <li>‘1234567’.match(/\d{1,3}/g),根据贪婪原则,结果是 ["123", "456", "7"] 。</li>     <li>不以“th”开头的单词匹配: /\b(?!th)\w+\b/ 。</li>     <li>对密码应用以下限制:其长度必须介于 4 到 8 个字符之间,并且必须至少包含一个数字: /^(?=.*\d).{4,8}$/ 。首先.{4,8} 表示与包含 4-8 个字符的字符串匹配;然后.*表示单个字符(除换行符 \n 外)零次或多次,且后面跟着一个数字,注意(?=)只匹配一个位置。</li>     <li>匹配一个中文字符: /[\u4e00-\u9fa5]/ 。</li>    </ol>    <p>当然,可能答案不唯一,不必较真啦~ 主要目的是回忆熟悉一下语法~</p>    <p>如果还不了解正则,可以前往正则表达式理论篇 了解哇~</p>    <h2>真正的实践来了</h2>    <p>要想在复杂性和完整性之间取得平衡,一个重要因素是要 <strong>了解将要搜索的文本</strong> 。</p>    <p>好的正则表达式:</p>    <ul>     <li><strong>只匹配期望的文本,排除不期望的文本</strong> ;</li>     <li><strong>易于控制和理解</strong> ;</li>     <li><strong>保证效率</strong> 。</li>    </ul>    <p>有时候处理各种极端情况会降低成本/收益的比例。所以某些情况下,不完全依赖正则表达式完成全部工作,比如某些字段用子表达式()括起来,让内存记忆下来,然后再用其他程序来验证。</p>    <p>不过本文还是从学习正则的角度出发,全部依赖正则表达式来写的哇~~</p>    <h2>匹配美元</h2>    <p>正则表达式: /^\$[0-9]+(\.[0-9][0-9])?$/ 。</p>    <p>分为四部分:</p>    <ul>     <li>^\$ 以美元符号开头。</li>     <li>[0-9]+ 至少包含一个数字。</li>     <li>(\.[0-9][0-9])? 由一个点和两位数组成,匹配0次或1次,因为可能是整数或者是小数。</li>     <li>$ 最后的$表示以数字结尾的。</li>    </ul>    <p>缺点:不能匹配$1,000</p>    <h2>匹配24小时制的时间,比如 09:59</h2>    <ul>     <li> <p><strong>小时部分</strong></p> </li>    </ul>    <p>方法一:分类逻辑为第一个数字(0、1、2),可以分为三部分:上午 00点到09点( <strong>0可选</strong> );白天10到19点;晚上20到23点。</p>    <p>因此有三个多选分支,得到的结果为:</p>    <pre>  <code class="language-javascript">0?[0-9]|1[0-9]|2[0-3]  </code></pre>    <p>还可以优化一下,合并前面的两个多选分支,得到:</p>    <pre>  <code class="language-javascript">[01]?[0-9]|2[0-3]  </code></pre>    <p>方法二:分类逻辑为第二个数字,可以分为两部分:[0-3]和[4-9]。为什么这么分?看看下面这个图就知道了,[0-3]多了一行(以2为第一个数字):</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/b5597cc990b4fd1fa588c0d524166cd6.png"></p>    <p>因此有两个多选分支,结果为:</p>    <pre>  <code class="language-javascript">[012]?[0-3]|[01]?[4-9]  </code></pre>    <ul>     <li> <p>分钟部分</p> </li>    </ul>    <p>分钟数比较简单,第一个数范围在0-5之间,第二个数在0-9之间,因此得到分钟数为:</p>    <pre>  <code class="language-javascript">[0-5][0-9]  </code></pre>    <ul>     <li> <p>最后的结果:</p> </li>    </ul>    <p>小时部分用(?:)包起来,起到一个分组的作用,且不保存匹配项;</p>    <p>冒号、分钟数拼起来;</p>    <p>最后加上一个分界 \b 表示单词的开始或结束,得到最终的结果:</p>    <pre>  <code class="language-javascript">/\b(?:[01]?[0-9]|2[0-3]):[0-5][0-9]\b/  // 或者  /\b(?:[012]?[0-3]|[01]?[4-9]):[0-5][0-9]\b/  </code></pre>    <ul>     <li> <p>验证:</p> </li>    </ul>    <pre>  <code class="language-javascript">var reg = /\b(?:[01]?[0-9]|2[0-3]):[0-5][0-9]\b/;  '现在是09:49点'.match(reg); // ["09:49"]  '现在是009:490点'.match(reg);  // null  </code></pre>    <p>其实这个结果不能说完全正确,首先你要明白这个正则用在什么地方,比如是数据验证或者</p>    <p>复杂的字符串搜寻替换。</p>    <p>情景一:填写表单中的字符串必须为24小时制的时间,那么可能第一个 \b 需要改成^,第二个 \b 改成 $ 。</p>    <p>情景二:用于复杂的字符串搜寻替换时,可能也会匹配这样子的字符串如’跑步用时19:50’,明显的,’19:50’表示19分50秒,而不是表示24小时制的时间19点50分。</p>    <h2>匹配IP地址</h2>    <p>IP地址的规则:点号分开的四个字段,每个字段在0-255之间。</p>    <ul>     <li> <p>第一步:</p> </li>    </ul>    <p>如果一个字段是一个数或两个数,肯定是在0-255的范围内的;</p>    <p>如果三位数,那么以0或者1开头的三位数也是合法的,即000-199。</p>    <p>从上面的陈述中我们就可以得到三个多选分支:</p>    <pre>  <code class="language-javascript">\d|\d\d|[01]\d\d  </code></pre>    <p>我们稍微合并一下这三个多选分支,得到:</p>    <pre>  <code class="language-javascript">[01]?\d\d?  </code></pre>    <ul>     <li> <p>第二步:</p> </li>    </ul>    <p>我们再来看以2开头的三位数:</p>    <p>第二位数小于5的时候,第三位数范围[0-9]都可以;第二位数等于5的时候,第三位数范围[0-5] ,因此得到两个多选分支:</p>    <pre>  <code class="language-javascript">2[0-4]\d|25[0-5]  </code></pre>    <ul>     <li> <p>第三步:</p> </li>    </ul>    <p>前两步合并起来,得到一个字段0-255的表示方法:</p>    <pre>  <code class="language-javascript">[01]?\d\d?|2[0-4]\d|25[0-5]  </code></pre>    <ul>     <li> <p>第四步:</p> </li>    </ul>    <p>四个字段合并起来,IP地址正则如下:</p>    <pre>  <code class="language-javascript">/^(?:[01]?\d\d?|2[0-4]\d|25[0-5])\.(?:[01]?\d\d?|2[0-4]\d|25[0-5])\.(?:[01]?\d\d?|2[0-4]\d|25[0-5])\.(?:[01]?\d\d?|2[0-4]\d|25[0-5])$/  </code></pre>    <p>点号要转义一下,^和$需要加上,否则可能匹配52123.3.22.993,因为其中的123.3.22.99是符合的。(?:)起到分组的作用,且不保存匹配项。</p>    <p>一些测试结果:</p>    <pre>  <code class="language-javascript">var reg = /^(?:[01]?\d\d?|2[0-4]\d|25[0-5])\.(?:[01]?\d\d?|2[0-4]\d|25[0-5])\.(?:[01]?\d\d?|2[0-4]\d|25[0-5])\.(?:[01]?\d\d?|2[0-4]\d|25[0-5])$/;    '123.11.22.33.44'.match(reg); // null  '52123.3.22.993'.match(reg);  // null  '123.11.22.33'.match(reg);  // ["123.11.22.33"]  '0.0.0.0'.match(reg);  // ["0.0.0.0"]  </code></pre>    <p>虽然0.0.0.0是合法的,但它是非法的IP地址,使用正则的否定顺序环视功能(零宽负向先行断言),可加上(?!0+.0+.0+.0+$) :</p>    <pre>  <code class="language-javascript">var reg = /^(?!0+.0+.0+.0+$)(?:[01]?\d\d?|2[0-4]\d|25[0-5])\.(?:[01]?\d\d?|2[0-4]\d|25[0-5])\.(?:[01]?\d\d?|2[0-4]\d|25[0-5])\.(?:[01]?\d\d?|2[0-4]\d|25[0-5])$/;    '123.11.22.33'.match(reg); // ["123.11.22.33"]  '0.0.0.0'.match(reg);  // null  </code></pre>    <p> </p>    <p>来自:https://aotu.io/notes/2016/12/07/regexp-practice/</p>    <p> </p>