正则表达式

正则表达式创建

正则表达式用于匹配字符串中的模式。

字面量创建

// 使用斜杠包裹
const regex = /东巴文/;
const regex2 = /东巴文/gi;  // 带修饰符

RegExp构造函数

// 使用构造函数
const regex = new RegExp("东巴文");
const regex2 = new RegExp("东巴文", "gi");

// 动态创建
const pattern = "东巴文";
const regex3 = new RegExp(pattern, "g");

两种方式对比

// 字面量:静态模式
const regex1 = /pattern/;

// 构造函数:动态模式
const userInput = "动态内容";
const regex2 = new RegExp(userInput);

// 字面量不需要转义
const regex3 = /\d+/;
const regex4 = new RegExp("\\d+");  // 需要双重转义

正则表达式语法

特殊字符

字符 说明 示例
. 任意字符(除换行) /a.c/ 匹配 "abc"
\d 数字 /\d/ 匹配 "5"
\D 非数字 /\D/ 匹配 "a"
\w 单词字符 /\w/ 匹配 "a"、"1"
\W 非单词字符 /\W/ 匹配 "@"
\s 空白字符 /\s/ 匹配 " "
\S 非空白字符 /\S/ 匹配 "a"
\b 单词边界 /\bword\b/
\B 非单词边界 /\Bword\B/

转义字符

// 需要转义的特殊字符
// ^ $ . * + ? { } [ ] \ | ( )

const regex1 = /\./;   // 匹配点号
const regex2 = /\$/;   // 匹配美元符号
const regex3 = /\*/;   // 匹配星号

字符类

基本字符类

// [abc]:匹配a、b或c
const regex1 = /[abc]/;
console.log(regex1.test("a"));  // true
console.log(regex1.test("d"));  // false

// [^abc]:匹配除a、b、c之外的字符
const regex2 = /[^abc]/;
console.log(regex2.test("a"));  // false
console.log(regex2.test("d"));  // true

// [a-z]:匹配a到z
const regex3 = /[a-z]/;
console.log(regex3.test("m"));  // true

// [0-9]:匹配0到9
const regex4 = /[0-9]/;
console.log(regex4.test("5"));  // true

// [a-zA-Z0-9]:匹配字母和数字
const regex5 = /[a-zA-Z0-9]/;

常用字符类

// 中文
const chinese = /[\u4e00-\u9fa5]/;
console.log(chinese.test("东"));  // true

// 手机号
const phone = /^1[3-9]\d{9}$/;

// 邮箱
const email = /^[\w.-]+@[\w.-]+\.\w+$/;

// 身份证号
const idCard = /^\d{17}[\dXx]$/;

量词

量词指定匹配的次数。

基本量词

量词 说明 示例
* 0次或多次 /a*/ 匹配 ""、"a"、"aaa"
+ 1次或多次 /a+/ 匹配 "a"、"aaa"
? 0次或1次 /a?/ 匹配 ""、"a"
{n} 恰好n次 /a{3}/ 匹配 "aaa"
{n,} 至少n次 /a{2,}/ 匹配 "aa"、"aaa"
{n,m} n到m次 /a{2,4}/ 匹配 "aa"、"aaa"、"aaaa"

贪婪与非贪婪

const str = "<div>内容</div>";

// 贪婪匹配(默认)
const greedy = /<.*>/;
console.log(str.match(greedy));  // ["<div>内容</div>"]

// 非贪婪匹配(加?)
const lazy = /<.*?>/;
console.log(str.match(lazy));  // ["<div>"]

量词示例

// 匹配手机号
const phone = /^1[3-9]\d{9}$/;

// 匹配QQ号(5-11位)
const qq = /^\d{5,11}$/;

// 匹配邮政编码
const postal = /^\d{6}$/;

// 匹配IP地址
const ip = /^(\d{1,3}\.){3}\d{1,3}$/;

锚点

锚点指定匹配的位置。

开始和结束

// ^:字符串开始
const start = /^东巴文/;
console.log(start.test("东巴文学习"));  // true
console.log(start.test("学习东巴文"));  // false

// $:字符串结束
const end = /东巴文$/;
console.log(end.test("学习东巴文"));  // true
console.log(end.test("东巴文学习"));  // false

// 完全匹配
const exact = /^东巴文$/;
console.log(exact.test("东巴文"));  // true
console.log(exact.test("东巴文学习"));  // false

单词边界

// \b:单词边界
const word = /\bword\b/;
console.log(word.test("word"));      // true
console.log(word.test("a word b"));  // true
console.log(word.test("password"));  // false

// \B:非单词边界
const notWord = /\Bword\B/;
console.log(notWord.test("password"));  // true

多行模式

const str = "第一行\n第二行\n第三行";

// 不使用m修饰符
const regex1 = /^第/g;
console.log(str.match(regex1));  // ["第"]

// 使用m修饰符
const regex2 = /^第/gm;
console.log(str.match(regex2));  // ["第", "第", "第"]

分组

分组用于捕获和引用匹配内容。

捕获组

// 使用括号创建捕获组
const regex = /(\d{4})-(\d{2})-(\d{2})/;
const str = "2024-01-15";
const match = str.match(regex);

console.log(match[0]);  // "2024-01-15"(完整匹配)
console.log(match[1]);  // "2024"(第一个捕获组)
console.log(match[2]);  // "01"(第二个捕获组)
console.log(match[3]);  // "15"(第三个捕获组)

命名捕获组

// 使用?<name>命名
const regex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const str = "2024-01-15";
const match = str.match(regex);

console.log(match.groups.year);   // "2024"
console.log(match.groups.month);  // "01"
console.log(match.groups.day);    // "15"

非捕获组

// 使用(?:)创建非捕获组
const regex = /(?:https?:\/\/)?([\w.-]+)/;
const str = "https://example.com";
const match = str.match(regex);

console.log(match[0]);  // "https://example.com"
console.log(match[1]);  // "example.com"(协议被非捕获组排除)

反向引用

// 使用\n引用第n个捕获组
const regex = /(\w)\1/;
console.log(regex.test("aa"));  // true(匹配重复字符)
console.log(regex.test("ab"));  // false

// 匹配HTML标签
const tag = /<(\w+)>.*<\/\1>/;
console.log(tag.test("<div>内容</div>"));  // true
console.log(tag.test("<div>内容</span>"));  // false

修饰符

修饰符改变正则表达式的行为。

常用修饰符

修饰符 说明 示例
g 全局匹配 /a/g 匹配所有"a"
i 忽略大小写 /a/i 匹配 "A"、"a"
m 多行模式 /^a/m 匹配每行开头
s dotAll模式 /./s 匹配包括换行
u Unicode模式 处理Unicode字符
y 粘连模式 从lastIndex开始匹配

修饰符使用

// g:全局匹配
const str = "东巴文东巴文";
console.log(str.match(/东巴文/g));  // ["东巴文", "东巴文"]

// i:忽略大小写
console.log(/hello/i.test("HELLO"));  // true

// m:多行模式
const multi = `第一行
第二行
第三行`;
console.log(multi.match(/^第/gm));  // ["第", "第", "第"]

// s:dotAll模式
console.log(/a.b/s.test("a\nb"));  // true

// u:Unicode模式
console.log(/\u{1F600}/u.test("😀"));  // true

RegExp方法

test

// test:检查是否匹配,返回布尔值
const regex = /东巴文/;
console.log(regex.test("学习东巴文"));  // true
console.log(regex.test("学习"));        // false

// 全局匹配时注意lastIndex
const regex2 = /a/g;
console.log(regex2.test("aaa"));  // true
console.log(regex2.lastIndex);    // 1
console.log(regex2.test("aaa"));  // true
console.log(regex2.lastIndex);    // 2

exec

// exec:返回匹配结果数组
const regex = /(\d+)/g;
const str = "a1b2c3";

let match;
while ((match = regex.exec(str)) !== null) {
    console.log(`找到: ${match[0]}, 位置: ${match.index}`);
}
// 找到: 1, 位置: 1
// 找到: 2, 位置: 3
// 找到: 3, 位置: 5

lastIndex

const regex = /a/g;
const str = "aaa";

regex.lastIndex = 1;  // 从索引1开始匹配
console.log(regex.exec(str));  // ["a", index: 1]

字符串正则方法

match

const str = "东巴文2024年01月15日";

// 非全局匹配
console.log(str.match(/\d+/));
// ["2024", index: 3, input: "东巴文2024年01月15日", groups: undefined]

// 全局匹配
console.log(str.match(/\d+/g));  // ["2024", "01", "15"]

// 未匹配返回null
console.log(str.match(/xyz/));  // null

matchAll

const str = "a1b2c3";
const regex = /([a-z])(\d)/g;

for (const match of str.matchAll(regex)) {
    console.log(match);
}
// ["a1", "a", "1", index: 0, ...]
// ["b2", "b", "2", index: 2, ...]
// ["c3", "c", "3", index: 4, ...]

search

// search:返回第一个匹配的索引
const str = "东巴文学习";
console.log(str.search(/学习/));  // 3
console.log(str.search(/不存在/));  // -1

replace

const str = "东巴文2024";

// 替换第一个匹配
console.log(str.replace(/\d/, "X"));  // "东巴文X024"

// 全局替换
console.log(str.replace(/\d/g, "X"));  // "东巴文XXXX"

// 使用捕获组
const date = "2024-01-15";
console.log(date.replace(/(\d{4})-(\d{2})-(\d{2})/, "$3/$2/$1"));
// "15/01/2024"

// 使用回调函数
const result = str.replace(/\d/g, (match, offset) => {
    return `[${match}]`;
});
console.log(result);  // "东巴文[2][0][2][4]"

split

const str = "a1b2c3";

// 使用正则分割
console.log(str.split(/\d/));  // ["a", "b", "c", ""]

正则表达式应用

表单验证

// 验证手机号
function validatePhone(phone) {
    return /^1[3-9]\d{9}$/.test(phone);
}

// 验证邮箱
function validateEmail(email) {
    return /^[\w.-]+@[\w.-]+\.\w+$/.test(email);
}

// 验证密码(8-20位,包含字母和数字)
function validatePassword(password) {
    return /^(?=.*[a-zA-Z])(?=.*\d)[a-zA-Z\d]{8,20}$/.test(password);
}

// 验证URL
function validateURL(url) {
    return /^https?:\/\/[\w.-]+(:\d+)?(\/[\w./-]*)?$/.test(url);
}

数据提取

// 提取URL参数
function getQueryParams(url) {
    const params = {};
    const regex = /[?&]([^=&]+)=([^&]*)/g;
    let match;
    
    while ((match = regex.exec(url)) !== null) {
        params[match[1]] = decodeURIComponent(match[2]);
    }
    
    return params;
}

console.log(getQueryParams("https://example.com?name=东巴文&age=1"));
// { name: "东巴文", age: "1" }

字符串处理

// 去除HTML标签
function stripHTML(html) {
    return html.replace(/<[^>]+>/g, "");
}

// 千分位格式化
function formatNumber(num) {
    return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

console.log(formatNumber(1234567));  // "1,234,567"

// 手机号脱敏
function maskPhone(phone) {
    return phone.replace(/(\d{3})\d{4}(\d{4})/, "$1****$2");
}

console.log(maskPhone("13812345678"));  // "138****5678"

下一步

掌握了正则表达式后,让我们继续学习:

  1. DOM基础 - 学习DOM操作
  2. DOM选择器 - 学习DOM选择
  3. DOM操作 - 学习DOM操作

东巴文(db-w.cn) - 让编程学习更简单

🔍 东巴文寄语:正则表达式是处理字符串的强大工具,虽然语法复杂,但掌握后能极大提高文本处理效率。从简单的匹配开始,逐步掌握高级用法。在 db-w.cn,我们帮你攻克正则表达式!