【正则表达式完全指南:从入门到精通】

本文将系统讲解正则表达式的语法规则和实战技巧,通过大量实例帮助你掌握这一强大的文本处理工具,提升开发效率。

📋 目录


一、正则表达式基础

1.1 什么是正则表达式

正则表达式(Regular Expression)是一种描述字符串模式的语言,用于:

  • 🔍 搜索:查找匹配的文本
  • 验证:检查格式是否正确
  • 🔄 替换:批量修改文本
  • 📤 提取:从文本中提取信息

1.2 基本语法

javascript 复制代码
// 创建正则表达式
const regex1 = /pattern/flags;        // 字面量
const regex2 = new RegExp('pattern', 'flags');  // 构造函数

// 常用标志(flags)
/pattern/g   // global: 全局匹配
/pattern/i   // ignoreCase: 忽略大小写
/pattern/m   // multiline: 多行模式
/pattern/s   // dotAll: .匹配换行符
/pattern/u   // unicode: Unicode模式
/pattern/y   // sticky: 粘性匹配

// 组合使用
/pattern/gi  // 全局+忽略大小写

1.3 普通字符与特殊字符

javascript 复制代码
// 普通字符:直接匹配
/hello/      // 匹配 "hello"
/abc123/     // 匹配 "abc123"

// 特殊字符需要转义
/\./         // 匹配 "."
/\*/         // 匹配 "*"
/\?/         // 匹配 "?"
/\\/         // 匹配 "\"
/\//         // 匹配 "/"

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

二、元字符与量词

2.1 字符类

javascript 复制代码
// 预定义字符类
\d    // 数字 [0-9]
\D    // 非数字 [^0-9]
\w    // 单词字符 [a-zA-Z0-9_]
\W    // 非单词字符 [^a-zA-Z0-9_]
\s    // 空白字符 [ \t\n\r\f\v]
\S    // 非空白字符
.     // 任意字符(除换行符)

// 示例
/\d{3}/.test('123')      // true
/\w+/.test('hello_123')  // true
/\s/.test(' ')           // true

2.2 自定义字符类

javascript 复制代码
// 字符集合 []
[abc]      // 匹配 a 或 b 或 c
[a-z]      // 匹配 a-z 任意字母
[A-Z]      // 匹配 A-Z 任意字母
[0-9]      // 匹配 0-9 任意数字
[a-zA-Z]   // 匹配任意字母
[a-zA-Z0-9]// 匹配字母或数字

// 否定字符集 [^]
[^abc]     // 匹配除 a、b、c 外的字符
[^0-9]     // 匹配非数字

// 示例
/[aeiou]/.test('hello')   // true (匹配元音)
/[^aeiou]/.test('hello')  // true (匹配辅音)

2.3 量词

javascript 复制代码
// 基本量词
*      // 0次或多次
+      // 1次或多次
?      // 0次或1次
{n}    // 恰好n次
{n,}   // 至少n次
{n,m}  // n到m次

// 示例
/a*/.test('')        // true (0次)
/a+/.test('aaa')     // true (多次)
/a?/.test('b')       // true (0次)
/a{3}/.test('aaa')   // true (恰好3次)
/a{2,4}/.test('aaa') // true (2-4次)

2.4 贪婪与非贪婪

javascript 复制代码
// 贪婪模式(默认):尽可能多匹配
const str = '<div>content</div>';
str.match(/<.*>/);    // ['<div>content</div>']

// 非贪婪模式:尽可能少匹配(加?)
str.match(/<.*?>/);   // ['<div>']

// 非贪婪量词
*?     // 0次或多次(非贪婪)
+?     // 1次或多次(非贪婪)
??     // 0次或1次(非贪婪)
{n,m}? // n到m次(非贪婪)

// 实际应用
const html = '<p>段落1</p><p>段落2</p>';
html.match(/<p>.*<\/p>/g);   // ['<p>段落1</p><p>段落2</p>']
html.match(/<p>.*?<\/p>/g);  // ['<p>段落1</p>', '<p>段落2</p>']

三、分组与引用

3.1 捕获分组

javascript 复制代码
// 基本分组 ()
const regex = /(\d{4})-(\d{2})-(\d{2})/;
const match = '2024-01-15'.match(regex);
// match[0] = '2024-01-15' (完整匹配)
// match[1] = '2024' (第1组)
// match[2] = '01' (第2组)
// match[3] = '15' (第3组)

// 命名分组 (?<name>)
const namedRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const namedMatch = '2024-01-15'.match(namedRegex);
// namedMatch.groups.year = '2024'
// namedMatch.groups.month = '01'
// namedMatch.groups.day = '15'

3.2 非捕获分组

javascript 复制代码
// 非捕获分组 (?:)
// 只分组不捕获,提高性能
const regex = /(?:https?:\/\/)?www\.(\w+)\.com/;
const match = 'https://www.example.com'.match(regex);
// match[1] = 'example' (只有一个捕获组)

// 对比
/(\d+)-(\d+)/.exec('123-456');     // ['123-456', '123', '456']
/(?:\d+)-(\d+)/.exec('123-456');   // ['123-456', '456']

3.3 反向引用

javascript 复制代码
// 引用前面的捕获组
// \1 引用第1组,\2 引用第2组...

// 匹配重复单词
const regex = /\b(\w+)\s+\1\b/gi;
'hello hello world'.match(regex);  // ['hello hello']

// 匹配成对标签
const tagRegex = /<(\w+)>.*?<\/\1>/;
'<div>content</div>'.match(tagRegex);  // ['<div>content</div>', 'div']

// 命名引用 \k<name>
const namedRef = /(?<word>\w+)\s+\k<word>/;
'hello hello'.match(namedRef);  // ['hello hello', 'hello']

3.4 替换中的引用

javascript 复制代码
// $1, $2... 引用捕获组
const str = '2024-01-15';
str.replace(/(\d{4})-(\d{2})-(\d{2})/, '$2/$3/$1');
// '01/15/2024'

// 命名引用 $<name>
str.replace(/(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/, '$<m>/$<d>/$<y>');
// '01/15/2024'

// 特殊替换模式
// $& - 匹配的子串
// $` - 匹配前的文本
// $' - 匹配后的文本
// $$ - 字面量$

'hello'.replace(/l/g, '[$&]');  // 'he[l][l]o'

四、断言与边界

4.1 边界匹配

javascript 复制代码
// 行首行尾
^      // 行首
$      // 行尾

/^hello/.test('hello world')  // true
/world$/.test('hello world')  // true
/^hello$/.test('hello')       // true (完全匹配)

// 单词边界
\b     // 单词边界
\B     // 非单词边界

/\bcat\b/.test('cat')         // true
/\bcat\b/.test('category')    // false
/\Bcat\B/.test('location')    // true

4.2 先行断言

javascript 复制代码
// 正向先行断言 (?=)
// 匹配后面是xxx的位置
/\d+(?=元)/.exec('100元')     // ['100']
/\d+(?=元)/.exec('100美元')   // null

// 负向先行断言 (?!)
// 匹配后面不是xxx的位置
/\d+(?!元)/.exec('100美元')   // ['100']
/\d+(?!元)/.exec('100元')     // ['10'] (贪婪匹配到10)

// 实际应用:密码验证
// 必须包含数字和字母
/^(?=.*\d)(?=.*[a-zA-Z]).{8,}$/

4.3 后行断言

javascript 复制代码
// 正向后行断言 (?<=)
// 匹配前面是xxx的位置
/(?<=\$)\d+/.exec('$100')     // ['100']
/(?<=¥)\d+/.exec('¥200')    // ['200']

// 负向后行断言 (?<!)
// 匹配前面不是xxx的位置
/(?<!\$)\d+/.exec('€100')     // ['100']

// 组合使用
// 提取引号内的内容
/(?<=")[^"]+(?=")/.exec('"hello"')  // ['hello']

4.4 断言实战

javascript 复制代码
// 千分位格式化
function formatNumber(num) {
  return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
formatNumber(1234567);  // '1,234,567'

// 密码强度验证
const strongPassword = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
// 至少8位,包含大小写字母、数字、特殊字符

// 提取URL参数
const url = 'https://example.com?name=test&age=18';
const params = {};
url.replace(/[?&]([^=]+)=([^&]*)/g, (_, key, value) => {
  params[key] = value;
});
// { name: 'test', age: '18' }

五、JavaScript正则API

5.1 RegExp方法

javascript 复制代码
// test() - 测试是否匹配
/\d+/.test('abc123');  // true

// exec() - 执行匹配,返回详细信息
const regex = /(\d+)/g;
let match;
while ((match = regex.exec('a1b2c3')) !== null) {
  console.log(match[0], match.index);
}
// '1' 1
// '2' 3
// '3' 5

// 注意:exec配合g标志会记住lastIndex
const re = /a/g;
re.exec('aaa');  // index: 0
re.exec('aaa');  // index: 1
re.exec('aaa');  // index: 2
re.exec('aaa');  // null

5.2 String方法

javascript 复制代码
// match() - 返回匹配结果
'hello123world456'.match(/\d+/);   // ['123']
'hello123world456'.match(/\d+/g);  // ['123', '456']

// matchAll() - 返回迭代器(ES2020)
const matches = 'a1b2c3'.matchAll(/(\w)(\d)/g);
for (const match of matches) {
  console.log(match);
}
// ['a1', 'a', '1', index: 0]
// ['b2', 'b', '2', index: 2]
// ['c3', 'c', '3', index: 4]

// search() - 返回首次匹配位置
'hello world'.search(/world/);  // 6
'hello world'.search(/xyz/);    // -1

// replace() - 替换
'hello'.replace(/l/g, 'L');     // 'heLLo'

// 函数替换
'hello'.replace(/./g, (char, index) => {
  return index % 2 === 0 ? char.toUpperCase() : char;
});  // 'HeLlO'

// split() - 分割
'a1b2c3'.split(/\d/);           // ['a', 'b', 'c', '']
'a1b2c3'.split(/(\d)/);         // ['a', '1', 'b', '2', 'c', '3', '']

5.3 常用技巧

javascript 复制代码
// 1. 动态构建正则
const keyword = 'hello';
const regex = new RegExp(keyword, 'gi');

// 转义特殊字符
function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

// 2. 获取所有匹配及分组
function getAllMatches(str, regex) {
  return [...str.matchAll(regex)].map(match => ({
    full: match[0],
    groups: match.slice(1),
    index: match.index
  }));
}

// 3. 替换回调函数
'hello world'.replace(/\b\w/g, char => char.toUpperCase());
// 'Hello World'

// 4. 条件替换
const text = 'cat dog cat';
text.replace(/cat|dog/g, match => {
  return match === 'cat' ? '🐱' : '🐶';
});  // '🐱 🐶 🐱'

六、实战案例大全

6.1 表单验证

javascript 复制代码
// 手机号验证(中国大陆)
const phoneRegex = /^1[3-9]\d{9}$/;
phoneRegex.test('13812345678');  // true

// 邮箱验证
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
emailRegex.test('test@example.com');  // true

// 身份证验证(简单版)
const idCardRegex = /^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/;

// URL验证
const urlRegex = /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([\/\w .-]*)*\/?$/;

// IP地址验证
const ipRegex = /^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/;

// 密码强度(8-20位,包含大小写字母和数字)
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,20}$/;

// 中文验证
const chineseRegex = /^[\u4e00-\u9fa5]+$/;
chineseRegex.test('你好');  // true

// 用户名(字母开头,允许字母数字下划线,4-16位)
const usernameRegex = /^[a-zA-Z][a-zA-Z0-9_]{3,15}$/;

6.2 文本处理

javascript 复制代码
// 去除HTML标签
function stripHtml(html) {
  return html.replace(/<[^>]*>/g, '');
}
stripHtml('<p>Hello <b>World</b></p>');  // 'Hello World'

// 提取所有链接
function extractLinks(html) {
  const regex = /href=["']([^"']+)["']/g;
  return [...html.matchAll(regex)].map(m => m[1]);
}

// 高亮关键词
function highlight(text, keyword) {
  const regex = new RegExp(`(${escapeRegExp(keyword)})`, 'gi');
  return text.replace(regex, '<mark>$1</mark>');
}

// 驼峰转下划线
function camelToSnake(str) {
  return str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
}
camelToSnake('getUserName');  // 'get_user_name'

// 下划线转驼峰
function snakeToCamel(str) {
  return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
}
snakeToCamel('get_user_name');  // 'getUserName'

// 首字母大写
function capitalize(str) {
  return str.replace(/\b\w/g, char => char.toUpperCase());
}
capitalize('hello world');  // 'Hello World'

6.3 数据提取

javascript 复制代码
// 提取日期
function extractDates(text) {
  const regex = /\d{4}[-/]\d{1,2}[-/]\d{1,2}/g;
  return text.match(regex) || [];
}
extractDates('日期:2024-01-15 和 2024/2/20');
// ['2024-01-15', '2024/2/20']

// 提取金额
function extractMoney(text) {
  const regex = /[¥$€]\s*[\d,]+\.?\d*/g;
  return text.match(regex) || [];
}
extractMoney('价格:¥199.00 或 $29.99');
// ['¥199.00', '$29.99']

// 提取手机号
function extractPhones(text) {
  const regex = /1[3-9]\d{9}/g;
  return text.match(regex) || [];
}

// 提取邮箱
function extractEmails(text) {
  const regex = /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g;
  return text.match(regex) || [];
}

// 解析查询字符串
function parseQueryString(url) {
  const params = {};
  const regex = /[?&]([^=]+)=([^&]*)/g;
  let match;
  while ((match = regex.exec(url)) !== null) {
    params[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
  }
  return params;
}
parseQueryString('?name=test&age=18');
// { name: 'test', age: '18' }

6.4 格式化处理

javascript 复制代码
// 千分位格式化
function formatThousands(num) {
  return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
formatThousands(1234567.89);  // '1,234,567.89'

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

// 邮箱脱敏
function maskEmail(email) {
  return email.replace(/(.{2}).*(@.*)/, '$1***$2');
}
maskEmail('test@example.com');  // 'te***@example.com'

// 身份证脱敏
function maskIdCard(id) {
  return id.replace(/(\d{6})\d{8}(\d{4})/, '$1********$2');
}
maskIdCard('110101199001011234');  // '110101********1234'

// 银行卡格式化
function formatBankCard(card) {
  return card.replace(/(\d{4})(?=\d)/g, '$1 ');
}
formatBankCard('6222021234567890123');
// '6222 0212 3456 7890 123'

// 清理多余空格
function cleanSpaces(str) {
  return str.replace(/\s+/g, ' ').trim();
}
cleanSpaces('  hello   world  ');  // 'hello world'

6.5 代码处理

javascript 复制代码
// 提取注释
function extractComments(code) {
  const singleLine = code.match(/\/\/.*$/gm) || [];
  const multiLine = code.match(/\/\*[\s\S]*?\*\//g) || [];
  return [...singleLine, ...multiLine];
}

// 移除注释
function removeComments(code) {
  return code
    .replace(/\/\/.*$/gm, '')
    .replace(/\/\*[\s\S]*?\*\//g, '');
}

// 提取函数名
function extractFunctionNames(code) {
  const regex = /function\s+(\w+)|(\w+)\s*=\s*(?:async\s*)?\([^)]*\)\s*=>|(\w+)\s*:\s*(?:async\s*)?function/g;
  const names = [];
  let match;
  while ((match = regex.exec(code)) !== null) {
    names.push(match[1] || match[2] || match[3]);
  }
  return names.filter(Boolean);
}

// 提取import语句
function extractImports(code) {
  const regex = /import\s+(?:{[^}]+}|\w+)\s+from\s+['"]([^'"]+)['"]/g;
  return [...code.matchAll(regex)].map(m => m[1]);
}

📊 正则表达式速查表

语法 说明 示例
. 任意字符 /a.c/ 匹配 abc
\d 数字 /\d+/ 匹配 123
\w 单词字符 /\w+/ 匹配 abc_123
\s 空白字符 /\s+/ 匹配空格
^ 行首 /^hello/
$ 行尾 /world$/
* 0次或多次 /a*/
+ 1次或多次 /a+/
? 0次或1次 /a?/
{n,m} n到m次 /a{2,4}/
[] 字符集 /[abc]/
() 分组 /(ab)+/
` `
(?=) 先行断言 /\d+(?=元)/
(?<=) 后行断言 /(?<=\$)\d+/

💡 总结

正则表达式核心要点:

  1. 掌握元字符. \d \w \s
  2. 理解量词* + ? {n,m} 及贪婪/非贪婪
  3. 善用分组:捕获分组、非捕获分组、反向引用
  4. 活用断言:先行断言、后行断言
  5. 熟悉API:test、exec、match、replace
  6. 多练实战:验证、提取、替换、格式化

正则表达式是开发者必备技能,熟练掌握能大幅提升文本处理效率!


💬 如果这篇文章对你有帮助,欢迎点赞收藏!有问题欢迎在评论区讨论~

相关推荐
烛阴2 天前
C# 正则表达式(4):分支与回溯引用
前端·正则表达式·c#
安且惜2 天前
根据正则表达式生成字符串
正则表达式
GDAL3 天前
vscode 使用正则查找替换
ide·vscode·正则表达式·编辑器
烛阴5 天前
C# 正则表达式(3):分组与捕获——从子串提取到命名分组
前端·正则表达式·c#
WangMing_X5 天前
C# 数据验证常用正则表达式
正则表达式
小北方城市网5 天前
第7课:Vue 3应用性能优化与进阶实战——让你的应用更快、更流畅
前端·javascript·vue.js·ai·性能优化·正则表达式·json
gis分享者5 天前
Bash 中如何使用正则表达式进行文本处理?(中等)
正则表达式·bash·shell·文本·处理
mofei121386 天前
正则表达式高级用法指南
python·正则表达式·零宽断言·原子分组
jayson.h7 天前
正则表达式
正则表达式