JS正则表达式和replace二三事

版权声明:本文为博主原创文章,若转载,请注明出处及作者,谢谢! https://blog.csdn.net/qq_38047742/article/details/83055370

引言

最近一段时间认真研究了一下正则表达式,这东西这是入门容易,越学越难,奇幻怪异的写法,各种变量配比。之前只是用的时候在网上现找,但是没想到,正则的水这么深,不去深入了解一下,还是不行,否则写出来的正则表达式非但不能完成任务,还有可能调入回溯陷阱,这次是搞明白了捕获应用和结合replace的替换,记录一下。

捕获应用

首先来说说捕获是什么:

官方话不说了,直接白话,就是正则表达式分组()中的所匹配出的字符串内容;每一个分组()代表一个捕获;在一个正则中,按()的顺序为第一组,第二组捕获;由于()具有分组和捕获双重意义,所以JS引擎会将所有的()都解释为捕获和分组,这会影响效率,因此在对不需要捕获的分组用(?:)标识,即可完成单纯的分组功能。

再说说去哪里能找到捕获的值:

1. String  match(regex): 这个方法返回值为数组,其中按索引排列,第0号是匹配的项,随后就是第1个捕获,第2个捕获......;

2. regex test (String) : 这个方法返回布尔值,捕获得去另一个地方找;

3. String.replace(regex, "$1"/function(str, $1,$2....)) : 这是字符串替换,第二参数为字符串时,可以直接用"$1,$2...."来获取到对应的捕获值,如果是函数,则函数的第二个参数开始也是对应的捕获值,注:这个函数的三个固定参数:第一个参数是匹配项,倒数第二个参数是匹配项索引,最后一个参数是原始字符串,而其他的均为捕获值,按顺序取就行。后面举例。

4. 正则表达式内部,利用“\1,\2...”可以作为反引用,匹配与之前对应捕获的内容,这个相当有用,可以简化表达式书写,化繁为简,将很多难以书写的表达式简化,比如匹配闭合标签,回文数。后面举例。

5. 以上所有与正则表达式相关的操作,都会在Regex对象中保留结果,其中Regex.$1-$9就保存了第1到9个捕获值,上述第2个方法的捕获就可以用这个方法获得,然而!!这个对象是共享的,只能保存最近一次操作的值,也就说,任何正则相关操作,都可以改变其值,所以用的时候,要慎重!

接下来就看一个捕获反引用的例子,回文数,判定,这个之前困扰我好久,但是理解了这个反引用,发现居然如此简单就解决了。上代码:

function testPalindrome(data) {
  let len = data.length,
	  part = Math.floor(len / 2),
	  reg_unit = "(\\w)",
	  reg_single = "\\w?",
	  group = "",
	  regex = "";
  //处理正则字符串
  for(let i = part; i--;) {
	  regex += reg_unit;
	  group += "\\" + (i + 1);
  }
  regex += reg_single + group;
  return new RegExp(regex).test(data);
}

变量part 为传入的字符串的一半长度,做为判断回文字符左半边数用,而reg_unit为判断用的基本正则分组,reg_single是回文数是否有一个中间单独字符的正则判断。接下来就用for循环进行正则表达式的拼写,左边半边是part个组,二而右边就是反引用倒序排列,加上reg_single,这样就可以针对输入的字符串,将回文数判定的正则拼合出来,然后判断是否是回文数。比如:正则表达式是(\w)(\w)\w?\2\1,对于level判定通过,而levee就不行,因为反引用/1是“l”。如此就完全不需要分隔字符串,再循环判断回文与否了。

replace应用

字符串的replace方法,用的比较多的可能也就是替换单个字符,即String.replace(regex, "XX")的形式,但是这样如果要替换多个字符,就比较麻烦了,循环,或者多写几遍。replace的第二参数可以是一个函数,而这个函数会被正则匹配出的每一个项调用,也就说,每匹配出一个,就调用一次函数,那么针对多个替换,只需要传如一个函数,写一个switch/case,一个方法全搞定,相当方便。举一个格式化日期的例子:

function formatDate(date, fmt) {
//正则表达式,准备工作等等就省略了,直接入主题
/*替换
 上面提到过回调函数的参数,这里只用第一个$catch,
 每次匹配的项,然后替换即可
*/
  fmt = fmt.replace(regex, function($catch) {
    switch(true) {
     case $catch.indexOf("y") > -1 && !year_done: //年
          year_done = true;
          return(date.getFullYear() + "").substring(4 - $catch.length);
     case $catch.indexOf("M") > -1 && !month_done: //月
          let month = date.getMonth() + 1;
          month_done = true;
          return $_replace($catch, month);
     case $catch.indexOf("d") > -1 && !day_done: //日
          let day = date.getDate();
          day_done = true;
          return $_replace($catch, day);
     case $catch.indexOf("H") > -1 && !hours_done: //时
          let hours = date.getHours();
          hours_done = true;
          return $_replace($catch, hours);
     case $catch.indexOf("m") > -1 && !minutes_done: //分
          let minutes = date.getMinutes();
          minutes_done = true;
          return $_replace($catch, minutes);
     case $catch.indexOf("s") > -1 && !seconds_done: //秒
          let seconds = date.getSeconds();
          seconds_done = true;
          return $_replace($catch, seconds);
     default:
         break;
    }
  });
  return fmt;
}

利用回调函数的第一个参数值,匹配项,通过一个判断语句,将替换的可能性列出,这样,只需要写一个方法,一个字符串中需要替换的字符,都将被替换,然后返回。当然,如果都要捕获的字段,可以在函数中后面几个参数获取到(见前文replace介绍);这样提高精细处理的效率,减少了代码的重复逻辑,还是很有用处的。

总结

正则是一潭很深的水,对于会水的人,驾轻就熟,游刃有余,然而不会的,真的会有“致命”风险,然而我对正则的研究并未达到游刃有余的地步,上述介绍也只是班门弄斧,欢迎高手指点!

个人网站:https://www.lakenqi.cn/, 欢迎大家光临!点此进入本文,浏览更多文章

猜你喜欢

转载自blog.csdn.net/qq_38047742/article/details/83055370