Skip to content

JavaScript 正则表达式

导航目录

词量修饰符

词量修饰符用于控制匹配字符出现的次数:

修饰符说明示例
*零到多次a* 匹配零个或多个 a
+一到多次a+ 匹配一个或多个 a
?零次或者一次a? 匹配零个或一个 a
{n}出现 n 次a{3} 匹配 3 个 a
{n,}出现 n 到多次a{2,} 匹配 2 个或更多 a
{n,m}出现 n 到 m 次a{2,4} 匹配 2 到 4 个 a

匹配规则

正则表达式中的匹配规则说明:

符号说明示例
****转义字符\d 匹配数字
.除换行符外的任意字符a.b 匹配 a 后跟任意字符再跟 b
^以哪一个字符作为开始^a 匹配以 a 开头的字符串
$以哪一个字符作为结束a$ 匹配以 a 结尾的字符串
\n换行符匹配换行符
\d0-9 数字\d+ 匹配一个或多个数字
\D非 0-9 数字\D+ 匹配一个或多个非数字
\w数字、字母、下划线\w+ 匹配一个或多个单词字符
\s空白字符\s+ 匹配一个或多个空白字符
\t一个制表符匹配制表符
\b匹配一个单词的边界\bword\b 匹配完整的单词 word
x|y匹配 x 或者 yx|y 匹配 x 或 y
[zyc]匹配 x 或者 y 或者 c[xyz] 匹配 x、y 或 z 中的任意一个
[^ab]除了 ab[^ab] 匹配除了 a 和 b 的任意字符
()分组(ab) 将 ab 作为一个分组
(?😃只匹配不捕获(?:ab) 匹配 ab 但不捕获
(?=)正向预查a(?=b) 匹配后面跟着 b 的 a
(?!)负向预查a(?!b) 匹配后面不跟着 b 的 a

exec 方法

核心特性:全局模式下也只会匹配一次,需要手动设置 lastIndex

js
let reg = /(\d+)/g;
console.log(reg.exec("2020-12-11")); // 2020

reg.lastIndex = 4;
console.log(reg.exec("2020-12-11")); // 12

reg.lastIndex = 7;
console.log(reg.exec("2020-12-11")); // 11

console.log("2020-12-11".match(reg)); // ['2020', '12', '11']

match 方法

核心特性:全部模式下会匹配所有

js
console.log("2020-12-11".match(reg)); // ['2020', '12', '11']

中括号中不存在多位数

应用场景:验证中括号中不存在多位数,如 [189] 应该是 [1|8|9]

js
let reg = /^[189]$/;
console.log(reg.test(1)); // true
console.log(reg.test(8)); // true
console.log(reg.test(9)); // true
console.log(reg.test(189)); // false

手机号码验证

应用场景:验证中国大陆手机号码格式

js
let reg = /^1[3456789]\d{9}$/;
console.log(reg.test(17624346544)); // true
console.log(reg.test(1762434654)); // false(位数不对)

最多 2 位小数

应用场景:验证小数格式,最多 2 位小数

规则说明

  1. \d+ 只能是数字
  2. (\.\d{1,2}) 小数位后只能是一到 2 位数字
  3. ? 表示小数部分可选,0 到一次
js
let reg = /^\d+(\.\d{1,2})?$/;
console.log(reg.test(10)); // true
console.log(reg.test(10.2)); // true
console.log(reg.test(10.22)); // true
console.log(reg.test(10.222)); // false(超过2位小数)

中文姓名验证

应用场景:验证中文姓名,2-4 个汉字

js
let reg = /^[\u4E00-\u9FA5]{2,4}$/;
console.log(reg.test("胡额")); // true
console.log(reg.test("张三")); // true
console.log(reg.test("李四")); // false(超过4个字)

身份证验证

应用场景:验证中国大陆身份证号码格式

js
let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})(\d{2})(\d)(\d|X|x)$/;
console.log(reg.exec("420881199411298114")); // 匹配成功

正则贪婪模式

核心概念:尽可能找最大的匹配

js
let reg = /\d+/g;
console.log("2019@2020".match(reg)); // ['2019', '2020'](贪婪匹配)

正则取消贪婪模式

核心概念:尽可能找最小的匹配

js
let reg = /\d+?/g;
console.log("2019@2020".match(reg)); // ['2', '0', '1', '9', '2', '0', '2', '0']

计算出现最多的字母

算法说明

  1. \1 匹配连续出现 [a-zA-Z])\1:连续的相同字母
  2. 字符先排序
  3. 遍历字符从索引结尾开始
  4. 正则匹配连续的字符
  5. 匹配到就终止循环
js
let str = "jabaambbjbcha";
str = str
  .split("")
  .sort((a, b) => a.localeCompare(b))
  .join("");
let flog = false;
let max = 0;
let arr = [];
for (let index = str.length; index > 0; index--) {
  if (flog) break;
  var reg = new RegExp(`([a-zA-Z])\\1{${index - 1}}`, "g");
  str.replace(reg, (content, $1) => {
    max = content.length;
    arr.push($1);
    flog = true;
  });
}
console.log(max, arr); // 输出:3 ['a', 'b']

首字母大写

应用场景:将字符串中每个单词的首字母大写

js
let str = "after a while , charley lowered his head . he laughed and asked";
str = str.replace(/\b([a-zA-Z]+)\b/g, (content) => {
  return content[0].toUpperCase() + content.substring(1);
});
console.log(str); // "After A While , Charley Lowered His Head . He Laughed And Asked"

日期格式化

应用场景:将日期时间格式化为指定模板

js
function formatTime(template = "{0}年{1}月{2}日 {3}时{4}分{5}秒") {
  let arr = this.match(/(\d+)/g);
  return template.replace(/\{(\d+)\}/g, ([, $1]) => {
    time = arr[$1] || "00";
    return time.length === 1 ? "0" + time : time;
  });
}

console.log(formatTime.call("2023-12-25", "{0}年{1}月{2}日 {3}时{4}分{5}秒"));
// "2023年12月25日 15时30分00秒"

获取 URL 参数

应用场景:从 URL 字符串中提取参数

js
function queryUrlParams() {
  let res = {};
  this.replace(/([^?=&#]+)=([^?=&#]+)/g, (...[, k, v]) => (res[k] = v));
  this.replace(/#([^?=&#]+)/g, (...[, v]) => (res["hash"] = v));
  return res;
}

console.log(
  queryUrlParams.call("https://example.com?name=John&age=25#section")
);
// { name: "John", age: "25", hash: "section" }

正则数组去重

应用场景:使用正则表达式对数组进行去重

js
let arr = [1, 23, 43, 1, 45, 33, 45, 11, 33];
let str = arr.sort((a, b) => a - b).join("@") + "@";
arr = [];
str.replace(/(\d+@)\1*/g, (content, $1) => {
  arr.push($1.replace("@", ""));
});
console.log(arr); // [1, 11, 23, 33, 43, 45]

实现 IndexOf 方法

核心原理:match 匹配到会返回当前字符的位置,未找到返回 null

js
String.prototype.myIndexOf = function (str) {
  let reg = new RegExp(str);
  let res = this.match(reg);
  return res === null ? -1 : res["index"];
};
console.log("aabbccb".indexOf("bbccb")); // 2
console.log("Blue Whale".indexOf("Blue")); // 0
console.log("Blue Whale".indexOf("Blute")); // -1
console.log("sfsdfsgssgdsgsdh".indexOf("h")); // 15
console.log("-----------------------");
console.log("aabbccb".myIndexOf("bbccb")); // 2
console.log("Blue Whale".myIndexOf("Blue")); // 0
console.log("Blue Whale".myIndexOf("Blute")); // -1
console.log("sfsdfsgssgdsgsdh".myIndexOf("h")); // 15

匹配 hello 字符串后边要跟着 3 个数字

应用场景:验证特定格式的字符串

js
var reg = /\d{1,3}(?=\d{3})/g;
var str = "123456789";
str.replace(reg, (content, a, b) => {
  console.log(content, a, b);
});
// 输出:123 456 789

实现数组 each 函数

核心特性

  1. 如何返回 false 终止循环
  2. 如果返回其他值,则改变原数组的值
js
Array.prototype.each = function (callback, self) {
  if (Object.prototype.toString.call([]) !== "[object Array]")
    return new Error("no is array");
  const content = self || this;
  for (let index = 0; index < this.length; index++) {
    let result = callback.call(content, index, this[index]);
    if (result === false) {
      break;
    }
    if (result) {
      this[index] = result;
    }
  }
};

let arr = [1, 2, 3, 4];
arr.each(function (index, item) {
  console.log(index, item);
  if (item === 2) {
    return 20; // 修改数组值
  }
});

console.log(arr); // [1, 20, 3, 4]

字母大小写转换

应用场景:将字符串中的字母大小写互换

js
let str = "Abc";
let newStr = str.replace(/([a-zA-Z])/g, (content) => {
  const tempStr = content.toLocaleUpperCase();
  return tempStr === content ? content.toLocaleLowerCase() : tempStr;
});
console.log(newStr); // "aBC"

URL 验证

应用场景:验证 URL 格式是否正确

规则说明

  • (?:(http|https|ftp):\/\/)?:协议部分,0 次或者 1 次,只匹配不捕获
  • ((?:[\w]+\.)+[a-z0-9]+):域名部分,xx.xx
  • ((?:\/[^/?#]\*)+):路径部分
  • (\?[^#]+):查询参数部分
  • (#.+):锚点部分
js
let reg =
  /^(?:(http|https|ftp):\/\/)?((?:[\w]+\.)+[a-z0-9]+)((?:\/[^/?#]*)+)?(\?[^#]+)?(#.+)?$/i;

console.log(reg.test("https://www.baidu.com/index.html?age=10#home")); // true
console.log(reg.test("baidu.com")); // false(缺少协议)
console.log(reg.test("https://www.baidu.com")); // true
console.log(reg.test("http://www.baidu.com.cn")); // true
console.log(reg.test("http://www.baidu.com.cn.net")); // true

同时满足字母大小写和数字

应用场景:验证密码等需要同时包含大小写字母和数字的字符串

规则说明

  • (?!^[a-zA-Z]+$):不能是全字母
  • (?!^[0-9]+$):不能是全数字
  • (?!^[a-z0-9]+$):不能是小写字母+数字
  • (?!^[A-Z0-9]+$):不能是大写字母+数字
  • ^[a-zA-Z0-9]{3,}$:只能是数字字母,至少 3 位
js
let reg =
  /(?!^[a-zA-Z]+$)(?!^[0-9]+$)(?!^[a-z0-9]+$)(?!^[A-Z0-9]+$)^[a-zA-Z0-9]{3,}$/;

console.log(reg.test("aaab")); // false(全字母)
console.log(reg.test("aaBva")); // false(小写字母+数字)
console.log(reg.test("11111144")); // false(全数字)
console.log(reg.test("adv44")); // false(小写字母+数字)
console.log(reg.test("AA44")); // false(大写字母+数字)
console.log(reg.test("aB4")); // true(符合要求)

必须有下划线

应用场景:验证用户名等必须包含下划线的字符串

规则说明

  • (?!^[a-z0-9A-Z]+$):不能是纯字母数字
  • ^\w{6,10}$:6-10 位字母数字下划线
  • (?=_)\w+:必须以下划线开头
js
let reg = /(?!^[a-z0-9A-Z]+$)^\w{6,10}$/;
console.log(reg.test("ssssdfd_")); // true
console.log(reg.test("_ssssfd_")); // true
console.log(reg.test("_sssfd_s11")); // true

let reg2 = /(?=_)\w+/;
console.log(reg2.test("_ssssdfd_")); // true
console.log(reg2.test("_ssssfd_")); // true
console.log(reg2.test("_sssfd_s11")); // true

userName 转换为 user_name

应用场景:将驼峰命名转换为下划线命名

js
let userName = "userName";
userName = userName.replace(/([A-Z])/g, (a) => `_${a.toLocaleLowerCase()}`);
console.log(userName); // "user_name"

user_name 转换为 userName

应用场景:将下划线命名转换为驼峰命名

js
let user_name = "user_name";
user_name = user_name.replace(/_(\w)/g, ([, $2]) => `${$2.toUpperCase()}`);
console.log(user_name); // "userName"