Skip to main content

正则表达式

一、正则表达式基础

正则表达式(RegExp)是用于匹配字符串模式的工具,在 JavaScript 中可通过以下两种方式创建:

// 字面量形式(推荐)
const pattern = /abc/i;

// 构造函数形式
const pattern = new RegExp('abc', 'i');

标志(Flags)

  • i:忽略大小写
  • g:全局匹配(找到所有匹配,而非第一个)
  • m:多行模式(^$ 匹配行首/行尾)
  • s:允许 . 匹配换行符
  • u:Unicode 模式(处理大于 \uFFFF 的字符)
  • y:粘性匹配(从 lastIndex 位置开始匹配)

二、元字符与特殊符号

字符描述示例
.匹配除换行符外的任意字符/a.b/ 匹配 acb, aab
\d匹配数字(等价于 [0-9]/\d{3}/ 匹配 123
\D匹配非数字(等价于 [^0-9]/\D+/ 匹配 abc
\w匹配单词字符(字母、数字、下划线)/\w{5}/ 匹配 hello
\W匹配非单词字符/\W/ 匹配空格、标点
\s匹配空白字符(空格、制表符、换行符)/\s+/ 匹配多个空格
\S匹配非空白字符/\S/ 匹配 a, 1, $
^匹配字符串开头(多行模式下匹配行首)/^hello/ 匹配 hello world
$匹配字符串结尾(多行模式下匹配行尾)/world$/ 匹配 hello world
[]匹配方括号内的任意字符/[aeiou]/ 匹配元音字母
[^]匹配不在方括号内的任意字符/[^0-9]/ 匹配非数字
|或操作/cat|dog/ 匹配 catdog

三、量词

量词描述示例
*匹配前一个元素 0 次或多次/a*/ 匹配 ``, a, aa
+匹配前一个元素 1 次或多次/a+/ 匹配 a, aa
?匹配前一个元素 0 次或 1 次(可选)/colou?r/ 匹配 colorcolour
{n}精确匹配 n 次/a{3}/ 匹配 aaa
{n,}至少匹配 n 次/a{2,}/ 匹配 aa, aaa
{n,m}匹配 n 到 m 次(包含 n 和 m)/a{2,4}/ 匹配 aa, aaa, aaaa

四、贪婪与非贪婪匹配

  • 贪婪匹配:默认行为,尽可能多地匹配。

    'aabab'.match(/a.*b/); // 返回 ['aabab']
  • 非贪婪匹配:通过 ? 启用,尽可能少地匹配。

    'aabab'.match(/a.*?b/); // 返回 ['aab']

五、分组与捕获

语法描述示例
(...)捕获组,提取匹配的子串/(\d{2})-(\d{2})/ 提取日期
(?:...)非捕获组,仅用于分组/a(?:b|c)/ 匹配 abac
\1, \2反向引用,引用前面的捕获组/(\w+) \1/ 匹配 hello hello

六、断言(零宽断言)

语法描述示例
(?=...)正向先行断言(后面必须匹配)/hello(?= world)/ 匹配 hello 后跟 world
(?!...)负向先行断言(后面不能匹配)/hello(?! world)/ 匹配 hello 但后面不能是 world
(?<=...)正向后行断言(前面必须匹配)/(?<=\$)\d+/ 匹配 $ 后的数字
(?<!...)负向后行断言(前面不能匹配)/(?<!\$)\d+/ 匹配前面不是 $ 的数字

七、JavaScript 中的 RegExp 方法

方法描述示例
test()检查字符串是否匹配,返回布尔值/abc/.test('abc') // true
exec()执行匹配,返回数组或 null/\d+/.exec('a123b') // ['123']
match()字符串方法,返回匹配结果'a1b2'.match(/\d/g) // ['1', '2']
matchAll()返回所有匹配的迭代器'a1b2'.matchAll(/\d/g)
replace()替换匹配的子串'hello'.replace(/h/, 'H') // 'Hello'
search()返回第一个匹配的索引'abc'.search(/b/) // 1
split()按匹配的模式分割字符串'a,b,c'.split(/,/) // ['a', 'b', 'c']

八、实用案例

1. 验证邮箱

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

2. 提取 URL 参数

const url = 'https://example.com?name=john&age=30';
const params = {};
url.replace(/[?&]([^=]+)=([^&]+)/g, (_, key, value) => {
params[key] = value;
});
// params: { name: 'john', age: '30' }

3. 替换 HTML 标签

const html = '<p>Hello <b>World</b></p>';
const text = html.replace(/<[^>]+>/g, '');
// text: 'Hello World'

4. 格式化电话号码

const phone = '1234567890';
const formatted = phone.replace(/(\d{3})(\d{3})(\d{4})/, '($1) $2-$3');
// formatted: '(123) 456-7890'

九、性能优化

  1. 预编译正则表达式

    // 避免在循环中重复创建相同的正则表达式
    const regex = /pattern/g;
    for (const str of array) {
    str.match(regex);
    }
  2. 简化复杂模式

    • 使用非捕获组 (?:...) 替代捕获组,减少内存开销。
    • 避免过度使用回溯(如嵌套量词)。

十、常见陷阱

  1. 点号不匹配换行符

    'a\nb'.match(/a.b/); // null
    'a\nb'.match(/a.b/s); // ['a\nb'](使用 s 标志)
  2. 全局标志与 lastIndex

    const regex = /a/g;
    regex.exec('ab'); // ['a']
    regex.exec('ab'); // null(lastIndex 已移动)
    regex.lastIndex = 0; // 重置 lastIndex
  3. Unicode 字符处理

    '😂'.match(/./); // ['�'](错误)
    '😂'.match(/./u); // ['😂'](使用 u 标志)

十一、总结

正则表达式是 JavaScript 中强大的字符串处理工具,掌握其核心概念(元字符、量词、分组、断言)和方法(testexecmatchreplace),可以高效解决各种文本处理需求。在实际应用中,建议使用工具(如 Regex101)辅助调试,并注意性能优化和边缘情况处理。