JavaScript 正则表达式实战:test/match/replace/捕获组

小飞兽 正则 9 次阅读 2026-07-29

Introduction

JavaScript 内置了强大的正则表达式支持,通过 RegExp 对象和 String 原型方法(test、match、replace、split)实现各种字符串处理。本指南通过大量实战案例,讲解 JavaScript 正则的各项 API 用法、捕获组的高级技巧、以及常见业务场景的解决方案。

基础语法

1. 创建正则表达式

const regex1 = /\d+/g;
const regex2 = /(?<year>\d{4})-(?<month>\d{2})/;
const regex3 = new RegExp(pattern, flags);
// flags: g i m s u y

2. String.prototype.test()

const isValidEmail = /^\w+@[\w.-]+\.\w+$/.test('test@example.com');
const isMobile = /^1[3-9]\d{9}$/.test('13812345678');
const isStrongPassword = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/.test('Pass1234');

3. String.prototype.match()

'2024-01-15'.match(/(\d{4})-(\d{2})-(\d{2})/);
'2024-01-15 2024-02-20'.match(/\d{4}-\d{2}-\d{2}/g);
'2024-01-15'.match(/(?<year>\d{4})-(?<month>\d{2})/);
[...'2024-01-15 2024-02-20'.matchAll(/(?<date>\d{4}-\d{2}-\d{2})/g)].map(m => m.groups.date);

4. String.prototype.replace()

'hello world'.replace('world', 'JavaScript');
'aabbcc'.replace(/b+/g, 'X');
'2024-01-15'.replace(/(\d{4})-(\d{2})-(\d{2})/, (m, y, mo, d) => ${y}年${mo}月${d}日);
'hello world'.replace(/(\w+)\s(\w+)/, '$2 $1');

5. String.prototype.split()

'a,b;c:d'.split(/[,;:]/);
'2024-01-15'.split(/(?=-)/);

完整代码示例

const validators = {
  isMobile(val) { return /^1[3-9]\d{9}$/.test(val); },
  isEmail(val) { return /^\w+([.-]?\w+)*@[\w-]+(\.[\w-]+)+$/.test(val); },
  isUrl(val) { return /^https?:\/\/(www\.)?[\w-]+(\.[\w-]+)+[\w\-._~:/?#[\]@!$&'()*+,;=.#%]+$/i.test(val); },
  isIdCard(val) { return /^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/.test(val); },
  isStrongPassword(val) { return /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/.test(val); },
  isIPv4(val) { return /^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$/.test(val); },
  isChineseName(val) { return /^[\u4e00-\u9fa5]{2,4}$/.test(val); }
};
console.log('手机号:', validators.isMobile('13812345678'));
console.log('邮箱:', validators.isEmail('test@example.com'));
console.log('URL:', validators.isUrl('https://www.example.com/path?query=1'));
console.log('身份证:', validators.isIdCard('11010119900101123X'));
console.log('强密码:', validators.isStrongPassword('MyPass123'));
console.log('IPv4:', validators.isIPv4('192.168.1.100'));
console.log('中文名:', validators.isChineseName('张三丰'));

const article = &lt;h1&gt;JavaScript 正则表达式完全指南&lt;/h1&gt;&lt;p&gt;作者:张三 | 发布于:2024-01-15 | 阅读量:1234&lt;/p&gt;&lt;p&gt;标签:前端开发、JavaScript、ES6+&lt;/p&gt;&lt;p&gt;联系邮箱:zhangsan@example.com&lt;/p&gt;&lt;p&gt;官网:https://example.com&lt;/p&gt;;
const metaMatch = article.match(/作者:([^|]+)\| 发布于:([^|]+)\| 阅读量:(\d+)/);
if (metaMatch) { const [, author, date, views] = metaMatch; console.log({ author: author.trim(), date: date.trim(), views: parseInt(views) }); }
const emails = [...article.matchAll(/[\w.-]+@[\w.-]+\.\w+/g)].map(m => m[0]);
console.log('邮箱:', emails);
const urls = [...article.matchAll(/https?:\/\/[^\s<>"']+/g)].map(m => m[0]);
console.log('URLs:', urls);

const dirtyText = 用户名: 张三 手机号: 13812345678 地址: 北京市朝阳区xxx路 100号 注册时间: 2024/01/15;
const clean = dirtyText.replace(/\s+/g, ' ').trim();
console.log('清洗空白:', clean);
const formatDate = (dateStr) => dateStr.replace(/(\d{4})\/(\d{2})\/(\d{2})/, '$1年$2月$3日');
console.log('日期格式化:', formatDate('2024/01/15'));
const toCamelCase = (str) => str.replace(/[-_]+(.)?/g, (_, c) => c ? c.toUpperCase() : '');
console.log('驼峰:', toCamelCase('user-name_of_the_app'));
const toSnakeCase = (str) => str.replace(/[A-Z]/g, c => _${c.toLowerCase()});
console.log('下划线:', toSnakeCase('userNameOfTheApp'));
const maskSensitive = (str) => str.replace(/(\d{3})\d{4}(\d{4})/g, '$1****$2');
console.log('手机脱敏:', maskSensitive('13812345678'));

const highlightKeywords = (text, keywords) => { const pattern = keywords.map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'); const regex = new RegExp((${pattern}), 'gi'); return text.replace(regex, '<mark>$1</mark>'); };
const text = 'JavaScript 正则表达式是前端开发的重要技能,正则表达式可以用于表单验证、数据提取等场景。';
console.log('高亮:', highlightKeywords(text, ['正则表达式', 'JavaScript', '前端']));

const parseRoute = (path) => { const regex = /^\/users\/(\d+)\/posts\/([\w-]+)$/; const match = path.match(regex); if (!match) return null; return { userId: match[1], postSlug: match[2] }; };
console.log('路由解析:', parseRoute('/users/123/posts/my-first-post'));

const logEntries = [2024-01-15 10:30:45] INFO: 用户登录成功 - user_id=1001
[2024-01-15 10:31:12] ERROR: 数据库连接失败 - error_code=5001
;
const logRegex = /\[(?<datetime>[\d-]+\s+[\d:]+\])\s+(?<level>\w+):\s+(?<message>.+?)\s+-\s+(?<extra>.+)/g;
for (const match of logEntries.matchAll(logRegex)) { console.log([${match.groups.level}] ${match.groups.message} (${match.groups.extra})); }

常见问题

    • RegExp 的 test 和 String 的 match 怎么选? 只判断"是否匹配"用 test(返回布尔值),需要获取匹配内容或捕获组用 match/matchAll。
    • 全局匹配(g)和捕获组一起用注意什么? 加了 g 标志的 match 不返回捕获组,需要捕获组时用 matchAll 或不带 g 标志的 match。
    • replace 回调函数的参数顺序是什么? 依次是:完整匹配、捕获组1、捕获组2...、捕获组N、匹配位置、原字符串。命名捕获组通过 groups 对象访问。
    • 正则表达式的 lastIndex 是什么? 使用 g 标志的 RegExp 对象有 lastIndex 属性,从该位置开始下一次匹配。在循环中使用时需要注意重置或每次创建新实例。

延伸阅读