Chapter 08 / 10

JavaScript RegExp 完全指南

掌握 JS 正则表达式的两种创建方式与所有 String/RegExp API

创建正则表达式

// 字面量语法(推荐)——编译时确定,性能更好
const re1 = /\d+/g

// 构造函数语法——运行时构建,适合动态模式
const re2 = new RegExp('\\d+', 'g')

// 动态构建正则(需要转义特殊字符)
function escapeRegex(str) {
    return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}
const keyword = escapeRegex(userInput)
const searchRe = new RegExp(keyword, 'gi')

String 方法

match()

const str = 'test1 test2 test3'

// 无 g 标志:返回第一个匹配(含捕获组)
str.match(/test(\d)/)
// → ['test1', '1', index: 0, input: ..., groups: undefined]

// 有 g 标志:返回所有匹配字符串数组(不含捕获组详情)
str.match(/test\d/g)
// → ['test1', 'test2', 'test3']

// 有 g 标志时,捕获组信息丢失——改用 matchAll
[...str.matchAll(/test(\d)/g)]
// → [Match('test1','1'), Match('test2','2'), Match('test3','3')]

matchAll()(ES2020)

const text = '2026-01-01 和 2026-12-31'
const dateRe = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/g

for (const m of text.matchAll(dateRe)) {
    console.log(m.groups)
    // { year: '2026', month: '01', day: '01' }
    // { year: '2026', month: '12', day: '31' }
}

replace() 和 replaceAll()

// 字符串替换
'hello world'.replace(/o/g, '0')  // 'hell0 w0rld'

// 捕获组引用($1, $2 或命名 $<name>)
'2026-03-26'.replace(
    /(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/,
    '$<d>/$<m>/$<y>'
)  // '26/03/2026'

// 函数替换(动态)
'price: 100 dollars'.replace(/\d+/g, n => n * 1.1)
// 'price: 110 dollars'

// $& 表示整个匹配,$` 前面的文本,$' 后面的文本
'foo bar'.replace(/\w+/g, '[$&]')  // '[foo] [bar]'

search()、split()、test()

// search:返回首个匹配的位置,无匹配返回 -1
'hello world'.search(/world/)  // 6

// split:按正则分割
'a1b2c3d'.split(/\d/)    // ['a','b','c','d']
'  hello   world  '.split(/\s+/).filter(Boolean)  // ['hello', 'world']

// test:测试是否匹配,返回布尔值
/^\d{4}$/.test('2026')   // true
/^\d{4}$/.test('20261')  // false

RegExp 方法

exec()

const re = /\d+/g
let m
while ((m = re.exec('a1 b22 c333')) !== null) {
    console.log(m[0], 'at', m.index)
}
// 1 at 1
// 22 at 4
// 333 at 8
WARNINGg 标志的正则有 lastIndex 状态。用同一个正则对象多次调用 exectest 时,记得注意 lastIndex 的位置,或者每次创建新的正则对象。

ES2018 新特性

// 命名捕获组
const { groups } = '2026-03-26'.match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/)
console.log(groups)  // { year: '2026', month: '03', day: '26' }

// 后顾断言(lookbehind)
'$100 €200'.match(/(?<=\$)\d+/g)   // ['100']

// s 标志(dotAll)
/foo.bar/s.test('foo\nbar')  // true(. 匹配换行)

// Unicode 属性转义
/\p{Letter}+/u.test('Hello')   // true
/\p{Script=Han}/u.test('汉')    // true(匹配汉字)

小结