正则表达式

基本

  • []这里面的某个字符匹配,注意里面的比如0-9 a-z不能降序填写,放置在里面的内容会当作字符处理,比如[.+]会匹配.+
  • {}限定数量
  • ^放在首部,开头匹配
  • $放在尾部,尾部匹配,起始和结束可以用于匹配所有字符数量是否相等
  • [^]表示非
  • \数字表示必须第几个原子组匹配的内容相同,
    • 嵌套分组时当括号套括号数的话就从左往右数,第几个左括号就是第几个原子组
    • 不记录分组
  • (?:)表示忽略当前组
  • (?<name>)可以给原子组起别名,通过$<name>访问,原子组一般通过$num访问,别名可以增加标识符
  • (?:str)先行断言,可以理解为条件,需要后面为对应的字符(str)才匹配
  • (?<=str)后行断言,需要前面为对应的字符(str)才匹配
  • (?!str)零宽负向先行断言,后面不是什么才匹配
  • (?<!str)零宽负向后行断言,前面不是什么才匹配

反斜杠

  • \s由于匹配空白,它会匹配空格 \n

  • \w匹配字母数字下划线,包括\d\W则相反

  • \p可以使用字符属性来匹配字符,需要和描述符u一起使用

let hd = "hou 2010";
// 下面的 \p{L} 表示匹配字母,L 可以换为其他类型
// http://cldr.unicode.org/unicode-utilities/list-unicodeset
console.log(hd.match(/\p{L}/gu)); // ['h', 'o', 'u']

模式

  • g描述符在使用match时会从头匹配到尾,但是后面的属性没有

  • s描述符中.可以匹配换行符

  • i描述符,大小写都匹配

  • m描述符,多行匹配

  • u表示按unicode(utf-8)匹配,主要针对多字节比如汉字

  • y表示在多次匹配时,不会忽略不能匹配的字符,在连续匹配的时候比如g效率更高,因为g所有字符都会尝试匹配

let hd = "后盾人QQ群:11111111,99999999,888888888我的看看";
let reg = /(\d+),?/y;
// 从头匹配并不行
reg.lastIndex = 7;
while ((res = reg.exec(hd))) qq.push(res[1]);
console.log(reg.exec(hd));

方法

字符串

  • match如果没有g只会匹配一次,如果有g则不会有剩余的属性,比如indexgroups

  • search接受一个正则来进行检索,输出索引

  • replace可以接受一个正则和一个替换的字符串

// 可以用 $数字 来表示匹配的原子组
let hd = "(010)999999999 (020)8888888";
let reg = /\((\d{3,4})\)(\d{7,8})/g;
console.log(hd.replace(reg, "$1-$2")); // 010-999999999 020-8888888

// 可以用 $& 表示匹配的字符本身
let he = "=后盾人=";
console.log(hd.replace(/后盾人/, "$&9")); // =后盾人9=

// $% 表示匹配部分前面的字符
console.log(hd.replace(/后盾人/, "$`")); // ===

// $' 表示匹配部分后面的字符
console.log(hd.replace(/后盾人/, "$'")); // ===
  • split可以接受一个字符串或是正则

  • matchAll可以得到一个迭代对象保存所有匹配的结果

// 低端浏览器实现 matchAll
String.prototype.matchAll = function (reg) {
  let res = this.match(reg);
  if (res) {
    let str = this.replace(res[0], "^".repeat(res[0].length));
    let match = str.matchAll(reg) || [];
    return [res];
  }
};

正则

  • test返回 boolean

  • exec也是只匹配一次,如果是g也就是全局模式下,它会有lastIndex属性,下次执行会从lastIndex处开始匹配

// exec 全局匹配
let str = "shishi";
// 注意必须是在全局模式下
let reg = /u/gi;
let result = [];
while ((res = reg.exec(str))) {
  result.push(res);
}
console.log(result);

概念

  • 贪婪匹配,即匹配更多的更好
let hd = "hddddd";
console.log(hd.match(/hd+/)); // hddddd
console.log(hd.match(/hd{1, 3}/)); // hddd

// 禁止贪婪
let hd = "hdddd";
// 后面加问号时它的匹配长度向一倾斜
console.log(hd.match(/hd+?/)); // hd,
console.log(hd.match(/hd{2}?/)); // hdd

a.match(/(.\.)+/g); // ["1.2.3."]
a.match(/(.\.)+?/g); // ["1.", "2.", "3."]

一些技巧

  • 匹配所有字符[\s\S]``[\d\D]都可以匹配所有字符

  • 批量使用正则进行密码强度校验

input.addEventListener("keyup", (e) => {
  const value = e.target.value;
  const regs = [
    /^[a-z0-9]{5,10}$/i,
    /[A-Z]/, // 必须有大写字母
    /0-9/, // 必须有数字
  ];
  let state = regs.every((e) => e.test(value));
  console.log(state);
});
  • 模糊电话号码
let users = `
  	向军电话:123456789
  	后盾人电话: 987654321
  `;
let reg = /(?<=\d{7})\d{4}/gi;
users = users.replace(reg, (v) => {
  return "*".repeat(4);
});
console.log(users);
  • 用户名关键字
const reg = /^(?!.*向军.*).*/i;
console.log(this.value.match(reg));

一些问题

  • 有时使用new创建正则会出问题,比如
"d" === "d"; // true
let price = 123.123;
let price1 = "dddd@ddddd";
// 这里会解析为 'd+.d+'
let reg = new RegExp("d+.d+");
reg.test(price); // false
reg.test(price1); // true
// 此时需要再加一个斜杠
let reg = new RegExp("\\d+\\.\\d+");