JavaScript || 正则表达式

uqsg8358 8年前
   <h2>1 为什么要用正则表达式?</h2>    <p>学习之前,多想想为什么要使用正则表达式,有助于理解。</p>    <p>正则表达式 regular expression 使用单个字符串来 <strong>描述某个句法规则</strong> ,计算机根据规则去匹配字符串中的内容。</p>    <ul>     <li> <p>正则表达式的性能高于常规字符串操作(省略循环、遍历等操作)</p> </li>     <li> <p>正则表达式仅用于字符串的操作</p> </li>    </ul>    <h2>2 常规字符串操作与正则表达式的比较</h2>    <p>要提取出字符串中 'ashx521dasbx34sasdz275dasdzxd897' 中连续的数字,并将结果保存在数组中 ['521', '34', '275', '897']</p>    <ol>     <li> <p>传统字符串操作:需要遍历整个字符串,判断每个字符是否在 '0'-'9' 之间再进行相应的操作</p> <pre>  <code class="language-javascript">/**   * 使用一个暂时变量tmp保存连续为数值时的字符串,间断后再统一加入数组内;   * 可能会出现最后一位是数字的情况,所以使用i<=str.length多走一次循环的else路径,将最后一组数组加入数组   *    */  function findNum_two(str) {      var arr = [];      var tmp = '';      // 遍历字符串,取出需要的数字      for(var i=0; i<=str.length; i++) {             if(str.charAt(i) <= '9' && str.charAt(i) >= '0') {              tmp += str[i];          } else {              if(tmp) {   // 如果tmp不为空                  arr.push(tmp);                  tmp = '';              }          }      }        return arr;  }  console.log(findNum_two(str));    //  [ '521', '34', '275', '897' ]</code></pre> </li>     <li> <p>使用正则表达式:只需使用字符串的 match() 方法去匹配指定的规则(正则表达式即可)</p> <pre>  <code class="language-javascript">function findNum (str) {      return str.match(/\d+/g);  }    console.log(findNum(str));   // [ '521', '34', '275', '897' ]</code></pre> </li>    </ol>    <h2>3 正则表达式写法</h2>    <ol>     <li> <p>字面量写法: var re = /\d+/gi;</p> </li>     <li> <p>构造函数写法: var re = new RegExp('\\d+', 'gi'); <strong> 注意两个 \\ ,因为JavaScript中 \ 需要转义 </strong></p> </li>    </ol>    <p style="text-align:center"><img src="https://simg.open-open.com/show/2f8800977c7f4d9645abfa4dc2bedab0.png"></p>    <h2>3.1 正则表达式中的转义字符</h2>    <p>转义字符:单独使用字母本身有意义;在前面加上 \ 后改变原有意义</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/b24e8696548e07dc71bae8c6abd3a0ed.png"></p>    <h2>3.2 量词</h2>    <p>用来描述相邻的前面的单个字符匹配规则出现的次数</p>    <ul>     <li> <p>量词使用 {a, b} 表示,其中 b 可以省略,意义不同</p> </li>    </ul>    <p style="text-align:center"><img src="https://simg.open-open.com/show/30ca5f01d753d5278c24bebfddc1ad1e.png"></p>    <h2>3.3 字符类</h2>    <ul>     <li> <p>使用 [] 描述一类字符, <strong>整体只代表一个字符</strong> ,表示该字符在某个范围内。</p> </li>     <li> <p>/a[0-9]c/ 匹配三位字符串,第一位是 a ,第三位是 c ,第二位是 '0'-'9' 之间的任何一位都可以匹配成功</p> </li>     <li> <p>[] 多种规则是 或 | 的关系: [0-9a-zA-Z] 等</p> </li>    </ul>    <p>整个字符类 [0-9a-zA-Z] 只代表一位字符</p>    <p>注意,字符类中的 ^ 表示非的意思,不在某个范围内 : [^\d] 表示非数字的字符</p>    <h2>3.4 修饰符</h2>    <ol>     <li> <p>g -- global :全局匹配,找到所有的匹配项,不是在第一个匹配后停止</p> </li>     <li> <p>i -- ignored :忽略大小写</p> </li>     <li> <p>m :多行,将开始字符 ^ 和结束字符 $ 视为在多行上工作(每匹配一行的开始和结束以 \n 和 \r 分割)</p> </li>     <li> <p>u :将模式视为Unicode序列点的序列</p> </li>    </ol>    <h2>3.5 匹配子项</h2>    <p>对于复杂的正则表达式,可以使用 () 将其拆分为多个部分, <strong> 在 replace(re, fn) 回调函数中可以简化匹配内容的操作 </strong></p>    <p>var re = /(\d+)(\w)(\S)/;</p>    <p>fn($0, $1, $2 ...)</p>    <ul>     <li> <p>$0 代表正则表达式本身匹配到的内容: (\d+)(\w)(\S)</p> </li>     <li> <p>$1 代表正则表达式的第一个匹配子项: (\d+)</p> </li>     <li> <p>$2 代表正则表达式第二个匹配子项: (\w)</p> </li>     <li> <p>...</p> </li>    </ul>    <h2>3.6 重复子项</h2>    <p>主要用于匹配字符串中重复的字符</p>    <ul>     <li> <p>var re = /(a)(b)(c)\1/; : \1 表示重复的第一个子项 (b) ,第4个位置的字符与第1个位置的字符相同</p> </li>     <li> <p>var re = /(a)(b)(c)\2/; : \2 表示重复的第二个子项 (b) ,第4个位置的字符与第2个位置的字符相同</p> </li>     <li> <p>var re = /(a)(b)(c)\3/; : \3 表示重复的第三个子项 (c) ,第4个位置的字符与第3个位置的字符相同</p> </li>     <li> <p>...</p> </li>    </ul>    <h2>3.7 逻辑或 |</h2>    <ul>     <li> <p>使用 | 代表逻辑或, | 左右两个操作数只要有一个满足要求即可</p> </li>    </ul>    <h2>3.8 开始、结束标记</h2>    <ul>     <li> <p>不在 [] 中使用 ^ , ^ 表示以最近的匹配字符规则开始整个匹配;</p> </li>     <li> <p>$ 表示以最近的匹配规则结束匹配</p> </li>    </ul>    <p>作用范围只是 ^ 之后的第一个子项; $ 前的第一个子项</p>    <h2>4 正则表达式的方法</h2>    <p>主要有4中方法用于操作正则表达式:</p>    <ol>     <li> <p>match() 、 replace() 、 search() 是字符串的操作方法</p> </li>     <li> <p>test() 、 exec() 是正则表达式对象的操作方法</p> </li>    </ol>    <h2>4.1 test()</h2>    <p>根据 RegExp 去匹配字符串,如果匹配成功,返回 true ;匹配失败返回 false 。 <strong>主要用于逻辑判断</strong></p>    <pre>  <code class="language-javascript">var str = "abxe2312dafxz";  var re = /\d+/;    re.test(str);   // true</code></pre>    <h2>4.2 search()</h2>    <p>根据 RegExp 去匹配字符串,返回第一个匹配成功字符串的首字符的索引;匹配失败返回 -1 。 <strong> 用于查找字符的索引,类似字符串的 indexOf() 方法 </strong></p>    <ul>     <li> <p>str.search(re)</p> </li>    </ul>    <h2>4.3 match()</h2>    <p>根据 RegExp 去匹配字符串,如果匹配成功,将匹配的结果保存在数组中返回;匹配失败返回 null 。 默认第一次匹配后便停止继续匹配,使用修饰符 g 进行全局匹配</p>    <ul>     <li> <p>str.match(re)</p> </li>    </ul>    <h2>4.4 replace(re, newstr) 方法</h2>    <p>根据 RegExp 去匹配字符串,如果匹配成功,将匹配的字符串更换为新的字符串 newstr 。</p>    <pre>  <code class="language-javascript">var str = 'a23gb';  var re = /\d+/;    str.replace(re, "xy");   //  'axygb'</code></pre>    <p>replace() 方法的第二个参数可以是回调函数,其参数是每次匹配成功获取的字符串。每次匹配成功都会执行一次回调函数</p>    <h2>5 实践</h2>    <h2>5.1 找到一个字符串中出现次数最多的字符及其出现的次数</h2>    <pre>  <code class="language-javascript">var str = '1231asdaegj71836178asdhasssasalsdhdzxbczaslazxcnnffajshdhgagsgdssssasdzzxda';    var str = str.split('').sort().join('');   // 按顺序的字符序列    var re = /(\w)\1+/g;    var length = 0;  var val = '';   // 保存出现次数最多的字符    // $0代表每次匹配到的字符,$1代表第一个正则表达式子项(\w)  str.replace(re, function ($0, $1) {  // 可以将匹配的字符当做变量操作      if($0.length > length) {          length = $0.length;          val = $1;    // $1代表每次匹配的字符      }  });  console.log(length);  console.log(val);</code></pre>    <h2>5.2 去掉字符串前后的空格</h2>    <ul>     <li> <p>var re = /^\s+|\s+$/g; ,使用字符串应用正则即可: str.replace(re, '')</p> </li>    </ul>    <h2>5.3 常用正则匹配规则</h2>    <ol>     <li> <p>QQ号: var re = /^[1-9]\d{4,11}$/; :第一位是1-9中的数字,最后也是数字,总共5-12位</p> </li>     <li> <p>中文匹配: var re = /[\u4e00-\u9fa5]/; :使用Unicode编码进行匹配</p> </li>     <li> <p>email : var re = /\w+@[a-z0-9]+(\.[a-z]+){1,3}/; :可能出现 .com.cn.net</p> </li>     <li> <p>身份证: var re = /[1-9]\d{14}|[1-9]\d{17}|[1-9]\d{16}x/i;</p> </li>     <li> <p>邮编: var re = /[1-9]\d{5}/;</p> </li>    </ol>    <h2>5.3 将常用正则表达式封装在一个对象中便于使用</h2>    <pre>  <code class="language-javascript">var re = {      email: /\w+@[a-z0-9]+(\.[a-z]+){1,3}/,      chinese: /[\u4e00-\u9fa5]/,      qq: /^[1-9]\d{4,11}$/,      id: /[1-9]\d{14}|[1-9]\d{17}|[1-9]\d{16}x/i,      trim: /^\s+|\s+$/  }</code></pre>    <p> </p>    <p>来自:https://segmentfault.com/a/1190000008729041</p>    <p> </p>