1.介绍 #

2.应用场景 #

3. 正则对象 #

3.1 创建正则对象 #

/pattern/flags
new RegExp(pattern[, flags])

3.1.1 字面量表示法 #

const regex = /apple/;

3.1.2 构造函数表示法 #

const regex = new RegExp("apple");

3.2 区别 #

3.2.1 变量 #

const regexpSource = "apple"
const regexp1 = /regexpSource/;
const regexp2 = new RegExp(regexpSource)

3.2.2 转义 #

特殊字符 字符含义 示例
\ 转义\ \\
' 单引号 \'
" 双引号 \"
\n 换行符 \n
\r 回车符 \r
\t 制表符 \t
\uXXXX Unicode 字符 \u03A9
const regexp2 = new RegExp('\'')
const regexp3 = new RegExp("\"")
const regexp4 = new RegExp("\n")
const regexp5 = new RegExp("\r")
const regexp1 = new RegExp("\\d")

3.3 方法和属性 #

3.3.1 test #

const regex = /apple/;
const str = "apple";
const result = regex.test(str);
console.log(result); // true
const str = 'hello hello ';
const regexp1 = /hello/;
let result;
console.log(regexp1.lastIndex);  // 0
result = regexp1.test(str);
console.log(result);  // true
console.log(regexp1.lastIndex);  // 0
result = regexp1.test(str);
console.log(result);  // true
console.log(regexp1.lastIndex);  // 0
result = regexp1.test(str);
console.log(result);  // true
console.log(regexp1.lastIndex);  // 0

const regexp2 = /hello/g;
console.log(regexp2.lastIndex);  // 0
result = regexp2.test(str);
console.log(result);  // true
console.log(regexp2.lastIndex);  // 5
result = regexp2.test(str);
console.log(result);  // true
console.log(regexp2.lastIndex);  // 11
result = regexp2.test(str);
console.log(result);  // false
console.log(regexp2.lastIndex);  // 0

3.3.2 global #

const regex1 = /hello/;
const regex2 = /hello/g;
console.log(regex2.global);
const str = "hello hello";
const result1 = str.match(regex1);
console.log(result1);
const result2 = str.match(regex2);
console.log(result2);

3.3.3 ignoreCase #

const regex1 = /apple/;
console.log('regex1.ignoreCase', regex1.ignoreCase); // false
const regex2 = /apple/i;
console.log('regex2.ignoreCase', regex2.ignoreCase); // true
const str = "Apple";
const result1 = regex1.test(str);
console.log('result1', result1); // false
const result2 = regex2.test(str);
console.log('result2', result2); // true

3.3.4 multiline #

const regex1 = /^world/;
const regex2 = /^world/m;
console.log(regex2.multiline);//true
const str = "hello \nworld you";
console.log(regex1.test(str)); // false
console.log(regex2.test(str)); // true

3.3.5 exec #

const regex = /hello/;
const str = "hello";
const result = regex.exec(str);
console.log(result); // [ 'hello', index: 0, input: 'hello']
const regex = /hello/g;
const str = "hello hello";
const result1 = regex.exec(str);
console.log(regex.lastIndex);//5
console.log(result1); // [ 'hello', index: 0, input: 'hello hello']
const result2 = regex.exec(str);
console.log(result2); //[ 'hello', index: 6, input: 'hello hello']

3.3.6 source #

const regex = /abc/i;
console.log(regex.source); // Output: "abc"

3.3.7 flags #

const regex = /abc/gi;
console.log(regex.flags); // "gi"

3.2.8 dotAll #

const regex1 = /abc./;
console.log(regex1.dotAll); // false
const regex2 = /abc./s;
console.log(regex2.dotAll); //true
console.log(regex1.test('abc\ndef')); //false
console.log(regex2.test('abc\ndef')); //true

3.3.10 sticky #

const regexp = /\d/y;
console.log(regexp.sticky);//true
const str = '1a2b3';
let result;
result = regexp.exec(str);
console.log(result);//[ '1', index: 0, input: '1a2b3']
console.log(regexp.lastIndex);//1
result = regexp.exec(str);
console.log(result);//null
console.log(regexp.lastIndex);//0
result = regexp.exec(str);
console.log(result);////[ '1', index: 0, input: '1a2b3']
console.log(regexp.lastIndex);//1

3.3.11 lastIndex #

const regex = /abc/g;
const str = "abc abc";
regex.exec(str);
console.log(regex.lastIndex); // Output: 3

3.3.12 hasIndices #

const regex1 = new RegExp('a(bc)(de)f', 'd');
console.log(regex1.hasIndices);
console.log(regex1.exec('abcdef'));

4.特殊字符 #

4.1 ^ #

const str1 = "hello world";
const regexp1 = /^hello/;
const result1 = regexp1.exec(str1);
console.log(result1); // [ 'hello', index: 0, input: 'hello world']

4.2 $ #

const str1 = "hello world";
const regexp1 = /world$/;
const result1 = regexp1.exec(str1);
console.log(result1); // [ 'world', index: 6, input: 'hello world']

4.3 单词边界 #

特殊符号 含义 示例代码
\b 单词边界 /\\bword\\b/.test("This is a word")
\B 非单词边界 /\\Bword\\B/.test("This is awordb")
const str1 = "hello world you";
const regexp1 = /\bworld\b/;
const result1 = regexp1.exec(str1);
console.log(result1);//[ 'world', index: 6, input: 'hello world you']

4.4 [] #

特殊符号 含义 示例代码
[abc] 可能是字符 "a"、"b" 或 "c" 的字符 /a[abc]d/ 匹配 "aad"、"abd" 或 "acd"
[^abc] 不是字符 "a"、"b" 或 "c" 的字符 /[^abc]/ 匹配任意一个不是 "a"、"b" 或 "c" 的字符
[a-z] 从 "a" 到 "z" 中的任意一个小写字母 /[a-z]/ 匹配任意一个小写字母
[A-Z] 从 "A" 到 "Z" 中的任意一个大写字母 /[A-Z]/ 匹配任意一个大写字母
[a-zA-Z] 包括小写和大写字母的任意一个字母字符 /[a-zA-Z]/ 匹配任意一个字母字符
[0-9] 从 "0" 到 "9" 中的任意一个数字字符 /[0-9]/ 匹配任意一个数字字符
const regexp1 = /[abc]/;
const str1 = "abcd";
const result1 = regexp1.exec(str1);
console.log('result1', result1); // result1 [ 'a', index: 0, input: 'abcd' ]

const regexp2 = /[^abc]/;
const str2 = "abcd";
const result2 = regexp2.exec(str2);
console.log('result2', result2); // result2 [ 'd', index: 3, input: 'abcd' ]

const regexp3 = /[^a-z]/;
const str3 = "aBcd";
const result3 = regexp3.exec(str3);
console.log('result3', result3); // result3 [ 'B', index: 1, input: 'aBcd' ]

const regexp4 = /[^A-Z]/;
const str4 = "aBcD";
const result4 = regexp4.exec(str4);
console.log('result4', result4); // result4 [ 'a', index: 0, input: 'aBcD' ]

const regexp5 = /[^a-zA-Z]/;
const str5 = "aBcd123";
const result5 = regexp5.exec(str5);
console.log('result5', result5); // result6 [ '1', index: 4, input: 'aBcd123' ]

const regexp6 = /[^0-9]/;
const str6 = "abcd123";
const result6 = regexp6.exec(str6);
console.log('result6', result6); // result5 [ 'a', index: 0, input: 'abcd' ]

4.5 \d #

const str1 = "a1b";
const regexp1 = /\d/g;
console.log(regexp1.exec(str1));//[ '1', index: 1, input: 'a1b']

4.6 \D #

const str2 = "a1b";
const regexp2 = /\D/g;
console.log(regexp2.exec(str2));//[ 'a', index: 0, input: 'a1b']

4.7 \w #

4.8 \W #

4.9 \s #

const str5 = "_1b @#";
const regexp5 = /\s/g;
console.log(regexp5.exec(str5));//[ ' ', index: 3, input: '_1b @#' ]

4.10 \S #

4.11 . #

let regexp1 = /he..o/;
console.log(regexp1.exec('hello'));//[ 'hello', index: 0, input: 'hello']

4.12 转义 #

需要注意的是,\ 本身也是一个转义字符,在正则表达式中需要使用两个反斜杠 \ 来匹配一个反斜杠字符

const str1 = "a.b";
const regexp1 = /\./g;
console.log(regexp1.exec(str1));//[ '.', index: 1, input: 'a.b']

5. 量词 #

特殊符号 含义 示例代码
* 匹配前面的子表达式零次或多次 /a*/
+ 匹配前面的子表达式一次或多次 /a+/
? 匹配前面的子表达式零次或一次 /a?/
{n} 匹配前面的子表达式恰好n次 /a{3}/
{n,} 匹配前面的子表达式至少n次 /a{2,}/
{n,m} 匹配前面的子表达式至少n次,至多m次 /a{2,4}/

5.1 * #

const str1 = "aaa";
const regexp1 = /^aaab*$/g;
const result1 = regexp1.exec(str1);
console.log(result1);//[ 'aaa', index: 0, input: 'aaa' ]

5.2 + #

const str2 = "aaab";
const regexp2 = /^aaab+$/g;
const result2 = regexp2.exec(str2);
console.log(result2);//[ 'aaab', index: 0, input: 'aaab' ]

5.3 ? #

const str3 = "aaabbb";
const regexp3 = /^aaab?/g;
const result3 = regexp3.exec(str3);
console.log(result3);//['aaab', index: 0, input: 'aaabbb']

5.4 {n} #

5.5 {n,} #

const str5 = "aaabbb";
const regexp5 = /^aaab{1,}/g;
const result5 = regexp5.exec(str5);
console.log(result5);//['aaab', index: 0, input: 'aaabbb']

5.6 {n,m} #

const str6 = "aaabbb";
const regexp6 = /^aaab{1,3}/g;
const result6 = regexp6.exec(str6);
console.log(result6);//[ 'aaabbb', index: 0, input: 'aaabbb']

5.7 懒惰匹配 #

const str = '<div>Content1</div><div>Content2</div>';
const regexp = /<div>(.*)<\/div>/g;
console.log(str.match(regexp)); // [ '<div>Content 1</div><div>Content 2</div>' ]
const str = '<div>Content 1</div><div>Content 2</div>';
const regexp = /<div>(.*?)<\/div>/g;
console.log(str.match(regexp)); // [ '<div>Content 1</div>', '<div>Content 2</div>' ]

6. 分组 #

6.1 组合 #

const str1 = "ababab";
const regexp1 = /(ab){3}/;
const result1 = regexp1.exec(str1);
console.log(result1);//[ 'ababab', 'ab', index: 0, input: 'ababab' ]

6.2 捕获 #

const str1 = "<div>(.+)</div>";
const regexp1 = /<div>(.+)<\/div>/;
const result1 = regexp1.exec(str1);
console.log(result1);//['<div>(.+)</div>','(.+)',index: 0,]

6.3 $ #

const regexp = /(\w+)\s(\w+)/;
const str = 'hello world';
const result = regexp.exec(str);
console.log(result);  // ['hello world', 'hello', 'world', index: 0, input: 'hello world']
console.log(result[1]);  // 'hello'
console.log(result[2]);  // 'world'
console.log(RegExp.$1);  // 'hello'
console.log(RegExp.$2);  // 'world'

6.4 | #

const regexp = /(hello|world)/;

const str1 = "hello";
const result1 = regexp.exec(str1);
console.log(result1);//[ 'hello', 'hello', index: 0, input: 'hello']

const str2 = "world";
const result2 = regexp.exec(str2);
console.log(result2);//[ 'world', 'world', index: 0, input: 'world']

6.5 (?:pattern) #

const str = 'hello123';
const regexp = /[a-z]+(?:\d+)/;
console.log(str.match(regexp)); // [ 'hello123', index: 0, input: 'hello123']

6.6 (?...) #

const str = '2023-05-11';
const regexp = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = str.match(regexp);
console.log(match.groups.year);  // 输出 "2023"
console.log(match.groups.month); // 输出 "05"
console.log(match.groups.day);   // 输出 "11"

6.7 正向肯定断言 #

const str = 'a1b2c3';
const regexp = /[a-z](?=\d)/g;
console.log(str.match(regexp)); // 输出 [ 'a', 'b', 'c' ]

6.8 正向否定断言 #

const str = 'a1b2c3';
const regexp = /\d(?!\d)/g;
console.log(str.match(regexp)); // [ '1', '2', '3' ]

6.9 反向引用 #

const str = '<div>str</div>';
const regexp = /<(\w+)>.*?<\/\1>/g;
console.log(str.match(regexp)))

6.10 反向肯定断言 #

const str = '123abc';
const regexp = /(?<=\d)[a-z]/g;
console.log(str.match(regexp)); // [ 'a' ]

6.11 反向否定断言 #

const str = 'a1b2c3';
const regexp = /(?<!\d)[a-z]/g;
console.log(str.match(regexp)); // [ 'a' ]

7.字符串方法 #

7.1 match #

7.1.1 非全局匹配 #

let regex = /to/;
let str = "string to search";
let matchResult = str.match(regex);
console.log(matchResult);//[ 'to', index: 7, input: 'string to search']
let execResult = regex.exec(str);
console.log(execResult);//[ 'to', index: 7, input: 'string to search']

7.1.2 全局匹配 #

let regex = /apple/g;
let str = "apple to apple";
let matchResult = str.match(regex);
console.log(matchResult);//[ 'apple', 'apple' ]
console.log(regex.lastIndex);//0
let execResult1 = regex.exec(str);
console.log(regex.lastIndex);//5
console.log(execResult1);//[ 'apple', index: 0, input: 'apple to apple']
let execResult2 = regex.exec(str);
console.log(regex.lastIndex);//14
console.log(execResult2);//[ 'apple', index: 9, input: 'apple to apple']

7.2 replace #

str.replace(regexp|substr, newSubstr|function)
const str = 'hello world';
const replaced = str.replace(/hello/g, 'hi');
console.log(replaced); // hi world

const name = 'zhang san';
const replacedName = name.replace(/(\w+)\s(\w+)/, '$2 $1');
console.log(replacedName); // san zhang

const result = 'background-color'.replace(/-([a-z])/g, function (match, letter) {
    return letter.toUpperCase();
});
console.log(result);
// 给 String.prototype 添加一个 replace 方法
String.prototype.replace = function (pattern, replacement) {
    // 初始化变量
    let match;
    let result = '';
    let lastIndex = 0;
    // 使用 while 循环和 RegExp.prototype.exec 方法找到所有匹配的部分
    while ((match = pattern.exec(this)) !== null) {
        // 将上一个匹配位置到当前匹配位置之间的字符串添加到结果中
        result += this.slice(lastIndex, match.index);
        // 检查 replacement 是否是字符串
        if (typeof replacement === 'string') {
            // 如果 replacement 是字符串,处理其中的 $1、$2 等引用
            let replaced = replacement.replace(/\$(\d+)/g, function (_, group1) {
                // 将 $1、$2 等引用替换为相应的捕获组
                return match[parseInt(group1)];
            });
            // 将替换后的字符串添加到结果中
            result += replaced;
            // 检查 replacement 是否是函数
        } else if (typeof replacement === 'function') {
            // 如果 replacement 是函数,将匹配的字符串和捕获组作为参数调用它,并将返回值添加到结果中
            result += replacement.apply(null, match);
        }
        // 更新 lastIndex 为当前匹配的结束位置
        lastIndex = pattern.lastIndex;
    }
    // 将最后一个匹配位置到字符串结束位置之间的字符串添加到结果中
    result += this.slice(lastIndex);
    // 返回结果
    return result;
};

const result = 'background-color'.replace(/-([a-z])/g, function (match, letter) {
    return letter.toUpperCase();
});
console.log(result); // 'backgroundColor'
const result2 = 'hello world'.replace(/(\w+) (\w+)/g, "$2 $1");
console.log(result2); // 'world hello'
str.search(regexp)
const str = 'hello world!';
const index = str.search(/world/i);
console.log(index); // 6

7.4 split #

str.split(separator, limit)
const str = 'aaa bbb  ccc';
console.log(str.split(/\s+/, 2));//[ 'aaa', 'bbb', 'ccc' ]

const str = 'aaa bbb   ccc;ddd,eee:fff';
console.log(str.split(/\W+/));//[ 'aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff' ]

const str = 'aaa bbb   ccc;ddd,eee:fff';
console.log(str.split(/(?:\s;,:)+/));//[ 'aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff' ]

7.5 trim #

const str = '   Hello, World!   ';
const trimmed = str.trim();
console.log(trimmed); // 输出 "Hello, World!"
function trim(str) {
  return str.replace(/^\s+|\s+$/g, '');
}

const str = '   Hello, World!   ';
const trimmed = trim(str);
console.log(trimmed); // 输出 "Hello, World!"

8. 正则案例 #

8.1 验证网址 #

function isValidUrl(str) {
    const regex = /^(https?:\/\/)/;
    return regex.test(str);
}
console.log(isValidUrl('http://www.baidu.com'));
console.log(isValidUrl('https://www.baidu.com'));
console.log(isValidUrl('httpss://www.baidu.com'));
console.log(isValidUrl('htt://www.baidu.com'));
console.log(isValidUrl('www.baidu.com'));

8.2 验证手机号 #

function isValidChinesePhoneNumber(str) {
  const regex = /^(?:\+86)?1[3-9]\d{9}$/;
  return regex.test(str);
}

const phone1 = "13012345678";
const phone2 = "+8618123456789";
const phone3 = "12012345678";
const phone4 = "1312345678";

console.log(isValidChinesePhoneNumber(phone1)); // true
console.log(isValidChinesePhoneNumber(phone2)); // true
console.log(isValidChinesePhoneNumber(phone3)); // false
console.log(isValidChinesePhoneNumber(phone4)); // false

8.3 验证身份证 #

8.3.1 简版 #

function isValidChineseID(str) {
    const regex = /^\d{6}\d{6,8}\d{3}[\dXx]?$/;
    return regex.test(str);
}
const id1 = "11010119900307123X";
const id2 = "11010119900307123x";
const id3 = "110101199003071234";
const id4 = "110101900307123";
console.log(isValidChineseID(id1)); // true
console.log(isValidChineseID(id2)); // true
console.log(isValidChineseID(id3)); // true
console.log(isValidChineseID(id4)); // false

8.3.2 专业版 #

8.3.2.1 身份证号 #
8.3.2.2 校验位 #
8.3.2.3 代码 #
function isValidChineseID(id) {
    const idPattern = /^(\d{6})(\d{2}((0[1-9])|(1[0-2]))(([0|1|2]\d)|3[0-1]))\d{3}$|^(\d{6})(19|20)\d{2}((0[1-9])|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}(\d|X)$/i;
    const matched = idPattern.test(id);
    if (!matched) return false;
    if (id.length === 15) return true;
    const checkDigit = calculateCheckDigit(id);
    return checkDigit === id[17].toUpperCase();
}

console.log(isValidChineseID("110101900307123")); // Output: true (15-digit ID)
console.log(isValidChineseID("450481197804234431")); // Output: true (18-digit ID)
console.log(isValidChineseID("123456789012345")); // Output: false (Invalid ID)

function calculateCheckDigit(id) {
    const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
    const checkDigits = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
    let sum = 0;
    for (let i = 0; i < 17; i++) {
        sum += parseInt(id[i]) * weights[i];
    }
    const remainder = sum % 11;
    return checkDigits[remainder];
}

8.4 验证中文姓名 #

function isValidChineseName(name) {
    const namePattern = /^[\u4e00-\u9fa5]+(\.[\u4e00-\u9fa5]+)*$/;
    return namePattern.test(name);
}

// Example usage
console.log(isValidChineseName("张三")); // true
console.log(isValidChineseName("马克.吐温")); // true
console.log(isValidChineseName("马克.吐温.吐司")); // true
console.log(isValidChineseName("John")); // false

8.5 验证用户名 #

function isValidString(str) {
  const regexp = /^[a-zA-Z0-9_]{6,16}$/;
    const regexp = /^\w{6,16}$/;
  return regexp.test(str);
}

// Example usage
console.log(isValidString("abc123_")); // Output: true
console.log(isValidString("abc!123")); // Output: false
console.log(isValidString("abc")); // Output: false

8.6 13-65 #

function isValidNumber(str) {
    const regexp = /^(1[3-9]|[2-5]\d|6[0-5])$/;
    return regexp.test(str);
}
console.log(isValidNumber('3'));
console.log(isValidNumber('13'));
console.log(isValidNumber('23'));
console.log(isValidNumber('33'));
console.log(isValidNumber('43'));
console.log(isValidNumber('53'));
console.log(isValidNumber('63'));
console.log(isValidNumber('73'));
console.log(isValidNumber("66")); //false

8.7 验证邮箱 #

function isValidEmail(email) {
    return /\w+@(\w+\.)+[a-z]{2,}/.test(email)
}

console.log(isValidEmail("zhang@qq.com")); // true
console.log(isValidEmail("zhang@126.com.cn")); // true

8.8 首字母大写 #

let str = 'good Good studY, Day a up';
// Good Good Study,Day Day Up

/* 
let result = str.replace(/\b\w+\b/g,function(matched){
    return matched.charAt(0).toUpperCase()+matched.slice(1).toLowerCase();
}); 
*/
let result = str.replace(/\b(\w)(\w*)\b/g,function(matched,group1,group2){
    return group1.toUpperCase()+group2.toLowerCase();
});
console.log(result);


8.9 最多字母 #

//验证字符串中哪个字母出现的次数最多,多少次
let str = 'abbcccdddccc';// abbccccccddd
//使用正则如何实现
let result = 
[...str]//把字符串转成字符数组
//['a','b','b','c','c','c','d','d','d','c','c','c']
//把相同字符排列在一起,把字符进行排序
.sort()//['a','b','b','c','c','c','c','c','c','d','d','d']
.join('')// abbccccccddd 把字符数组重新连接成字符串
//正则里面的\1代表引用第一个分组的值
 //用正则匹配字符串,会返回数组,每个元素都是一个连续的字符序列
.match(/([a-z])\1*/g)//['a','bb','cccccc','ddd']
//按每个元素,也就是字符串的长度进行升序排序
.sort((a,b)=>a.length-b.length)//['a','bb','ddd','cccccc']
//找到最后面那一个最长的
.pop();
console.log(`${result[0]}出现了${result.length}`);

//不用正则如何实现
let charsCount = {}
for (let c of str){
   if(typeof charsCount[c]  === 'undefined'){
    charsCount[c]=1;
   }else{
    charsCount[c]+=1;
   }
}
const entries = Object.entries(charsCount);
let maxEntry=null;
for(let entry of entries){
    if(maxEntry){
        if(entry[1] > maxEntry[1]){
            maxEntry=entry;
        }
    }else{
        maxEntry=entry;
    }
}
//console.log(maxEntry[0],maxEntry[1]);

8.10 千分符 #

String.prototype.withThousandsSeparator = function () {
    //return this.replace(/\B(?=(\d{3})*$)/g, ',');
    return this.replace(/\d{1,3}(?=(\d{3})+$)/g, (matched) => {
        return matched + ',';
    });
}
let str = '123456789';
console.log(str.withThousandsSeparator());

8.11 格式化时间 #

String.prototype.format = function(inputFormat,outputFormat){
    //1.声明一个数组,存放时间的各个部分的占位符
    const timeParts = [];
    //2.把输入的格式,是一个字符串,转化成一个正则表达式
    //并且记录各个部分的占位符到timeParts
    const regexpSource = inputFormat.replace(/(YYYY|MM|DD|hh|mm|ss)/g,(matched)=>{
        timeParts.push(matched);
        return matched==='YYYY'?'(\\d{4})':'(\\d{2})';
    });
    //通过正则的源码生成正则的实例
    let regexp = new RegExp(regexpSource);
    //用正则表达式匹配当前的字符串,把各个时间部分的值存到各个分组里
    const resultArray = this.match(regexp);
    let groups = resultArray.slice(1);
    //const [,...groups] = this.match(regexp);
    //计算时间部分对象,key是占位符的名称YYYY, 值是对应的时间值 2023
    const dateValues = timeParts.reduce((memo,part,index)=>{
        memo[part]=groups[index];//YYYY=2023
        return memo;
    },{});
    //用实际匹配到的值替换输出的格式字符串,把各个占位符变成实际的值
    return outputFormat.replace(/(YYYY|MM|DD|hh|mm|ss)/g,(matched)=>dateValues[matched]);
}

//定义一个原始的日期格式
let dateStr = '2023#23#05 12@13@15';
let result = dateStr.format(
    'YYYY#DD#MM hh@mm@ss',
    'YYYY-MM-DD hh:mm:ss'
);
console.log(result);//2023-05-23 12:13:15

8.12 URL #

let url = `http://username:password@www.baidu.com:80/path/to/myfile.html?key1=value1&key2=value2#SomewhereInTheDocument`;
//必填 protocal hostname    http://localhost
//其它的都是可有可无的
function parseUrl(url,parseQuery=false){
   //1.声明一个正则表达式
   let pattern = /^(https?):\/\/([^:]+):([^@]+)@([^:]+):(\d+)([^?]+)\?([^#]+)#(.+)/;
   //有当前的url地址和正则进行匹配
   let result = url.match(pattern);
   //因为每一个组成部分都对应一个分组,那么可以从result中取出分组的值
   const [,protocal,username,password,hostname,port,pathname,query,hash] = result;
   //创建返回值
   let parseResult=  {
    protocal,username,password,hostname,port,pathname,query,hash
   }
   //host=主机名:端口号
   parseResult.host=hostname+":"+port;
   //path=路径名?查询字符串
   parseResult.path = pathname+'?'+query;
   //如果需要把query字符串变成对象的话
   if(parseQuery){
    let queryObj = {};
    //key1=value1&key2=value2
    parseResult.query.replace(/([^=&]+)=([^=&]+)/g,function(matched,key,value){
        queryObj[key]=value;
    });
    parseResult.query =queryObj;//parseResult.key1=value1
   }
   return parseResult
}
let result = parseUrl(url,true);
console.log(result);
/**
{
    protocal:'http',
    username:'username',
    password:'password',
    hostname:'www.baidu.com',
    port:'80',
    host:'www.baidu.com:80',
    pathname:'/path/to/myfile.html',
    query:'key1=value1&key2=value2',
    query:{key1:value1,key2:value2},
    path:'/path/to/myfile.html?key1=value1&key2=value2',
    hash:'SomewhereInTheDocument'
}
 */
//let url = `http://username:password@www.baidu.com:80/path/to/myfile.html?key1=value1&key2=value2#SomewhereInTheDocument`;
function parseUrl(url,parseQuery=false){
   let pattern = /(?<protocal>https?|ftp|file):\/\/((?<username>[^:]+):(?<password>[^@]+)@)?(?<hostname>[^:\s?]+)(:(?<port>\d+))?(?<pathname>[^?\s]+)?(?<query>\?[^#]+)?(?<hash>#.+)?/;
   let result = url.match(pattern);
   const {protocal,username='',password='',hostname,port=80,pathname='/',query='',hash=''} = result.groups;
   let parsedResult =  {
    protocal,
    username,
    password,
    hostname,
    port,
    pathname,
    query,
    hash
   }
   if(parseQuery){
    let queryObj = {};//  query: '?name=zhufeng&age=16',
    query.slice(1).replace(/([^=&]+)=([^=&]+)/g,function(_,key,value){
        queryObj[key]=value;
    });
    parsedResult.query = queryObj;
   }
   return parsedResult;
}
let url1 = 'http://localhost?name=zhufeng&age=16';

let result = parseUrl(url1,true);
console.log(result);

附录 #

RegExp静态属性 #

属性/方法名 描述与作用
RegExp.input 静态属性,代表默认的当前正在匹配的输入字符串
RegExp.lastIndex 静态属性,代表默认的下一次匹配开始的索引位置
RegExp.$1-$9 静态属性,代表匹配到的第1至9个子表达式的内容
RegExp.$_ 静态属性,代表默认的当前正在匹配的输入字符串
RegExp.leftContext 静态属性,代表当前匹配结果左侧的文本
RegExp.rightContext 静态属性,代表当前匹配结果右侧的文本
RegExp.$& 静态属性,代表当前匹配结果的文本
RegExp.$` 静态属性,代表当前匹配结果左侧的文本
RegExp.$' 静态属性,代表当前匹配结果右侧的文本
RegExp.$+ 静态属性,代表匹配到的最后一个子表达式的内容
RegExp.$* 静态属性,代表匹配到的所有子表达式的内容
RegExp.$_ 静态属性,代表默认的当前正在匹配的输入字符串
RegExp.$input 静态属性,代表默认的当前正在匹配的输入字符串
RegExp.$regexp 静态属性,代表当前正则表达式对象的源代码
RegExp.$1-$99 静态属性,代表匹配到的第1至99个子表达式的内容
RegExp.$_ 静态属性,代表默认的当前正在匹配的输入字符串
RegExp.$& 静态属性,代表当前匹配结果的文本
RegExp.$+ 静态属性,代表匹配到的最后一个子表达式的内容
RegExp.$* 静态属性,代表匹配到的所有子表达式的内容
RegExp.$_ 静态属性,代表默认的当前正在匹配的输入字符串
RegExp.$` 静态属性,代表当前匹配结果左侧的文本
RegExp.$' 静态属性,代表当前匹配结果右侧的文本
RegExp.$1-$99 静态属性,代表匹配到的第1至99个子表达式的内容
RegExp.$_ 静态属性,代表默认的当前正在匹配的输入字符串
RegExp.$& 静态属性,代表当前匹配结果的文本

RegExp实例属性 #

属性/方法名 描述与作用
source 正则表达式的源代码
global 是否开启全局匹配模式
ignoreCase 是否忽略大小写
multiline 是否开启多行匹配模式
lastIndex 当前正则表达式匹配完成后,下一次匹配开始的索引位置
exec(str) 在一个字符串中执行匹配搜索,返回一个数组或 null
test(str) 在一个字符串中测试是否存在匹配,返回 true 或 false
toString() 返回表示 RegExp 对象的字符串
toLocaleString() 返回表示 RegExp 对象的本地化字符串
valueOf() 返回 RegExp 对象的原始值