四、js正则第 4 部分


31、为低端浏览器定义原型方法matchAll

<body>
  <p>
    <span>wujunjie.fun</span>
    <span>junjie.com</span>
    <span>wu.cn</span>
  </p>
</body>
<script>
  String.prototype.matchAll = function(reg) {
    let res = this.match(reg);
    if(res) {
      // repeat返回一个新字符串,表示将原字符串重复n次,x.repeat(3)就是xxx
      // 这个作用就是将匹配到的内容每一个字母都替换成^
      let str = this.replace(res[0], '^'.repeat(res[0].length));
      let match = str.matchAll(reg) || [];
      return [res, ...match];
    }
    return null;
  }
  let hd = document.querySelector('p').innerHTML;
  const resArr = hd.matchAll(/<span>([\s\S]+?)<\/span>/i);
  console.log(resArr);
  if(resArr.length) {
    resArr.forEach(item => {
      console.log(item[1]);
    })
  }
</script>

32、使用exec完成全局匹配

// 由于exec方法具有lastindex属性,也可以完成全局匹配
let str = document.querySelector('p').innerHTML;
let reg = /<span>([\s\S]+?)<\/span>/gi;
// exec必须加上全局匹配才会带上lastIndex,不然一直匹配第一个会死循环
while(res = reg.exec(str)) {
  console.log(res[1]);
}

33、search、match、matchAll、split、replace

<body>
  <p>
    <span>wujunjie.fun</span>
    <span>junjie.com</span>
    <span>wu.cn</span>
  </p>
</body>
<script>
  const html = document.querySelector('p').innerHTML;
  let reg = /<span>([\s\S]+?)<\/span>/gi;
  // 正则的方法有 reg.test(str); reg.exec(str); 
  // 字符串的方法有 str.replace(reg, function(){}); str.match(reg); str.matchAll(reg); str.search(reg); str.split(reg);

  // search方法:搜索符合条件的结果并返回索引值,全局匹配也只会返回第一个结果
  let str = 'wujunjie.fun';
  console.log(str.search(/u/g));
  console.log(html.search(reg));
  // match方法:匹配单个返回单个结果并且带有信息,全局匹配会返回所有的结果,但是没有其他信息
  console.log(str.match(/u/));
  console.log(html.match(reg));

  // matchAll方法:放回一个迭代器对象,我们遍历迭代器能拿到每个结果,并且每个结果都带有其他信息
  for (const iterator of html.matchAll(reg)) {
    console.log(iterator);
  }

  // split方法:用正则拆分字符串
  let hd = '2020/03-23';
  let hdReg = /[-\/]/;
  console.log(hd.split(hdReg));

  // replace方法:用正则完成字符串的替换
  // 注意替换的时候有g与没有g是由很大区别的
  console.log(hd.replace(/[-\/]/g,'^'));

  let wu = '(010)9999999 (020)8888888';
  let wuReg = /\((\d{3,4})\)(\d{7,8})/g;
  // 这里的$1和$2就是分组1和分组2
  // 注意注意注意注意:$&就是分组0,也就是我们匹配到的内容,这个很好用
  console.log(wu.replace(wuReg, '$1-$2'));
</script>

34、原子组别名优化正则

<body>
  <p>
    <span>wujunjie.fun</span>
    <span>junjie.com</span>
    <span>wu.cn</span>
  </p>
</body>
<script>
  // 普通的$1和$2,\1和\2等就是别名,还有自定义的别名,格式为:?<名称>
  // 注意:写在哪个分组里面就是给哪个分组命名
  const str = document.querySelector('p').innerHTML;
  let reg = /<span>(?<con>[\s\S]+?)<\/span>/gi;
  console.log(str.replace(reg,'<h1>$<con></h1>'));

  // 注意groups里面装的就是别名信息
  // 别名其实很好用
</script>

35、test、exec

<body>
  <p>
    <span>wujunjie.fun</span>
    <span>junjie.com</span>
    <span>wu.cn</span>
  </p>
</body>
<script>
  // 正则的方法
  // test方法:reg.test(str),返回true和false;
  // exec方法:res = reg.exec(str),注意必须要用全局匹配,每次只返回一个结果
  // exec自身带有lastIndex属性,配合循环遍历出每一个结果,结果都带有信息
  const str = document.querySelector('p').innerHTML;
  let reg = /<span>(?<con>[\s\S]+?)<\/span>/gi; 
  while(res = reg.exec(str)){
    console.log(res);
  }
</script>

36、断言匹配?=以及应用

<body>
  <p><span>我叫吴俊杰,吴俊杰加油!!!</span></p>
</body>
<script>
  // 把第二个吴俊杰加上链接
  // 这里的条件就是后面连接加油(?=加油)的吴俊杰加上a标签
  let str = document.querySelector('p span');
  let reg = /吴俊杰(?=加油)/g
  str.innerHTML = str.innerHTML.replace(reg,`<a href='wujunjie.fun'>$&</a>`)
  
  // 第二个例子
  let newStr = `
  js,200元,300次
  php,300.00元,100次
  node.js,180元,260次
  `;

  let newReg = /(\d+)(\.00)?(?=元)/gi;
  newStr = newStr.replace(newReg,(v, ...args) => {
    console.log(args);
    args[1] = args[1] || '.00';
    return args.splice(0,2).join('');
  })
  console.log(newStr);
</script>

37、断言匹配?<=以及应用

<body>
  <p>
    <span>我叫吴俊杰,吴俊杰加油!!!</span>
    <a href="https://baidu.com"></a>
    <a href="https://yahoo.com"></a>
  </p>
</body>
<script>
  // ?<=断言:和上一个相反,这个指前面是什么
  let hd = 'wujunjie2019nihao170'
  const reg = /(?<=wujunjie)\d+/gi;
  console.log(hd.match(reg));

  const main = document.querySelector('p');
  const newReg = /(?<=href=(['"])).+(?=\1)/gi;
  main.innerHTML = main.innerHTML.replace(newReg, 'https://www.wujunjie.fun');

  // 第二个例子
  let users = `
  吴俊杰电话:18325516903
  另一个人电话:00000000000
  `;
  let reg2 = /(?<=\d{7})\d{4}/gi;
  console.log(users.replace(reg2, '****'));
</script>

38、断言匹配?!以及应用

<body>
  <input type="text" name="username">
</body>
<script>
  // ?!断言:后面不是什么
  let str = 'wujunjie2019nihao';
  let reg = /[a-z]+(?!0)/gi;
  console.log(str.match(reg));

  // 第二个例子,文本框不能包含俊杰两个字,屏蔽敏感词
  const input = document.querySelector(`[name='username']`);
  input.addEventListener('keyup', function() {
    // 这里的断言就是从开始的后面不能出现俊杰两个字,点代表任意字符,*代表零个或多个,也就是说俊杰两个字可以放在任何位置
    // 需要注意的是这里的起止和结束符号都是作用在5到6位字母符号上的
    const reg = /^(?!.*俊杰.*).*/gi;
    console.log(this.value.match(reg));
  })
</script>

39、断言匹配?<!以及应用

<body>
  <p>
    <a href="https://www.wujunjie.com/1.jpg">1.jpg</a>
    <a href="https://oss.wujunjie.com/2.jpg">2.jpg</a>
    <a href="https://cdn.wujunjie.com/3.jpg">3.jpg</a>
    <a href="https://wujunjie.com/4.jpg">吴俊杰</a>
  </p>
</body>
<script>
  // ?<!断言:前面不是什么
  let hd = 'wujunjie2019nihao';
  let reg = /(?<!\d+)[a-z]+/gi;
  console.log(hd.match(reg));

  // 第二个例子,使用断言排除法统一数据
  const str = document.querySelector('p');
  const newReg = /https:\/\/([a-z]+)?(?<!oss)\..+?(?=\/)/gi;
  str.innerHTML.replace(newReg,(v) => {
    console.log(v);
  })
</script>

40、工作遇到的一些正则情况

// 一、需求是这样的,我们需要拿

// 1、先拿到value和backupValue
let { questionText: { value, backupValue } } = needHandleContent.groups[0].questions[0];
// 2、通过匹配提取value中的sentence标签及其内容,返回一个数组
const sentenceArr = value.match(/<sentence[\s\S]+?<\/sentence>/g);
// 3、遍历数组,把每一个sentence标签里面的内容拿出来去匹配backupValue对应的值,同时把它给替换掉
// 由于每条数据都不能出错所以有一条错误直接抛异常然后研发查看
try {
  if (sentenceArr.length) {
    sentenceArr.forEach(sentenceValue => {
      // 这里用原子组包裹中间的内容是可以拿到中间的文本的
      sentenceValue.replace(/<sentence[\s\S]+?>([\s\S]+?)<\/sentence>/g, ($1, $2) => {
        if ($1 && $2) {
          // 这里的$2就是文本,拿着文本去backupValue中匹配并替换
          // 需要注意的是如果文本里有一些符号,会被当作元字符,所以需要对这些符号做转义
          const str =$2.replace(/(\?|\\|\/)/g, item => '\\' + item);
          const reg = new RegExp(str, 'g');
          backupValue = backupValue.replace(reg, (res) => {
            if (res) {
              return sentenceValue;
            } else {
              throw new Error();
            }
          })
        } else {
          throw new Error();
        }
      });
    })
  } else {
    throw new Error();
  }
} catch {
  return this.$Message.warning('短文文本未能成功拼接,麻烦联系研发人员处理!');
}


// 二、去除文本的前后空格
  const textTrim = (text):string => {
    if(!text) return '';
    var regex = /^(&nbsp;|\s)+|(&nbsp;|\s)+$/g;
    text = text.replace(regex, '');
    return text;
  }

// 三、匹配文本的首尾标签
let startTags = item.match(/^<[^>]+>/);
let endTags = item.match(/<[^>]+>$/);

// 四、通过对象形式创建正则表达式
// const regex = /h(\w+?)l(\w+?)o/g;
// 对比一下对象形式
const regex = new RegExp('h(\\w+?)l(\\w+?)o', 'g')
const str = 'hello world, hello javascript, hello regex';
let match;
while((match = regex.exec(str)) !== null) {
    console.log(match);
}

// 五、用一些特殊字符切割字符串
// 比如说我要用★分割下列的句子
const text = '请以"前端开发、朋友"为话★2.请以"把握结构、我是测试考察点、观点态度"为考★3.写一段有100个单词的英文对★4.每段对话少于10★5.使用常见词代替长难词★6.使用短句代替长句★7.使用初中生能理解的单词'
const resArr = text.match(/[^★]+/g);// 全局匹配除了★的文本

// 六、前视断言和后视断言
// 下面这个是用来匹配什么的????
/(?<=).+?(?=\))/
// 这个正则表达式用于匹配位于中文全角冒号 : 后面和全角右括号 ) 之前的任意字符序列。正则表达式中所使用的是正向后视断言 (?<=...) 和正向前视断言 (?=...)

// (?<=:): 正向后视断言,用于匹配紧跟在一个全角冒号 : 后的位置。
// .+?: 禁止贪婪模式下的一个或多个任意字符。
// (?=\)): 正向前视断言,用于匹配紧靠在一个全角右括号 ) 之前的位置

// 例如:在以下文本中:
// 这是一个示例:要匹配的内容)
// 应用上述正则表达式将会匹配到 “要匹配的内容”。它不包含冒号和括号在内,因为冒号和括号被用作定界符,但不包括在匹配结果中。

41、零个?多个?一个?

// \s? 表示零个或一个空白字符。这包括空格、制表符等。
// \s* 表示零个或多个空白字符。这包括空格、制表符等。
// \s+ 表示一个或多个空白字符。这包括空格、制表符等。

文章作者: 吴俊杰
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 吴俊杰 !
 上一篇
一、ES6+整体篇上 一、ES6+整体篇上
ES6+有趣且重要,如果你不懂它,那你一定写不出优雅的代码,你也一定看不懂别人写的代码。它是基础也是基石,学起来吧......
2024-12-03
下一篇 
三、js正则第 3 部分 三、js正则第 3 部分
因为AI的存在,导致js在正则并不是很重要,AI会给你一个完美的正则写法,当然你需要做到的就是能看懂,所以还是做些了解吧......
2024-12-03
  目录