Skip to content

正则表达式

正则表达式用于描述“字符串模式”。它最适合做匹配、提取、校验和替换。

什么时候会用到

常见场景包括:

  • 判断输入格式是否符合要求
  • 从字符串中提取某一段内容
  • 批量替换文本
  • 按某种模式切分字符串

创建方式

字面量

js
const re = /abc/

构造函数

js
const re = new RegExp('abc')

如果模式来自变量拼接,通常使用 RegExp 构造函数更方便。

正则由什么组成

一条正则通常可以拆成两部分:

  • 模式本体
  • 标志位
js
const re = /abc/gi

这里:

  • abc 是模式
  • gi 是标志位

最常见的基础语法

普通字符

js
;/abc/.test('abc123') // true

元字符

js
/\d/.test('1') // true
/\w/.test('a') // true
/\s/.test(' ') // true
/./.test('x') // true

常见的一组是:

  • \d:数字
  • \w:字母、数字、下划线
  • \s:空白符
  • .:任意单个字符

对应的反义写法:

  • \D
  • \W
  • \S

锚点

锚点用于描述位置,而不是字符本身:

js
/^abc/.test('abc123') // true
/abc$/.test('123abc') // true
/\bcat\b/.test('cat dog') // true

最常见的是:

  • ^:开头
  • $:结尾
  • \b:单词边界

字符类

字符类用于表达“这一位可以是哪些字符”:

js
/[abc]/.test('b') // true
/[a-z]/.test('k') // true
/[0-9]/.test('8') // true
/[^abc]/.test('z') // true

量词

量词用于表达“前面的模式出现多少次”:

js
/a*/.test('aaa') // true
/a+/.test('aaa') // true
/a?/.test('') // true
/a{3}/.test('aaa') // true
/a{2,5}/.test('aaaa') // true

贪婪与惰性

量词默认是贪婪的,会尽量多吃字符:

js
;/.+/.exec('aaa')[0] // 'aaa'

在量词后面加 ? 可以改成惰性匹配:

js
;/.+?/.exec('aaa')[0] // 'a'

这在提取标签、括号内容、包裹片段时非常常见。

分组与捕获

捕获组

js
const match = /(\d{4})-(\d{2})-(\d{2})/.exec('2025-08-16')

console.log(match[1]) // 2025
console.log(match[2]) // 08
console.log(match[3]) // 16

非捕获组

js
;/(?:abc)+/.test('abcabc') // true

命名捕获组

js
const match = /(?<year>\d{4})-(?<month>\d{2})/.exec('2025-08')

console.log(match.groups.year) // 2025

选择

使用 | 表示“满足其中一个”:

js
;/(cat|dog)/.test('dog') // true

断言

断言用于表达“某个位置前后必须满足什么条件”,但本身不消费字符。

js
/\d+(?=px)/.exec('100px')[0] // '100'
/(?<=\$)\d+/.exec('$99')[0] // '99'

常见的是:

  • (?=...):正向先行断言
  • (?!...):正向否定断言
  • (?<=...):反向先行断言
  • (?<!...):反向否定断言

标志位

最常用的是:

  • g:全局匹配
  • i:忽略大小写
  • m:多行模式
  • s:dotAll
  • u:Unicode
  • y:粘连模式
js
;/hello/gi.test('HELLO') // true

常用方法

test

最适合做真假判断:

js
;/\d+/.test('abc123') // true

exec

最适合拿匹配结果和捕获组:

js
const match = /\d+/.exec('abc123')

console.log(match[0]) // '123'

match

由字符串调用,适合快速拿结果:

js
'abc123'.match(/\d+/) // ['123']

replace

js
'abc123'.replace(/\d+/g, '#') // 'abc#'

split

js
'a,b,c'.split(/,/) // ['a', 'b', 'c']

g 标志要特别注意

g 的正则在反复执行 test()exec() 时,会受到 lastIndex 影响:

js
const re = /\d/g

console.log(re.test('1')) // true
console.log(re.test('1')) // false

这里不是模式突然失效,而是正则对象自己记住了上一次匹配位置。

如果只是做一次性真假判断,通常不需要带 g

正则适合和不适合的边界

适合:

  • 固定格式校验
  • 文本提取
  • 批量替换

不太适合:

  • 复杂语法解析
  • 强语义结构分析
  • 可读性要求极高的长规则

当一条正则已经长到难以解释时,通常应该考虑拆分逻辑或改用解析器。

使用建议

  • 先明确目标是“判断、提取、替换”中的哪一种。
  • 简单模式优先,别一开始就把所有规则塞进一条超长正则。
  • 捕获组只在确实需要取值时再用。
  • 遇到带 gtest() / exec() 时,记得想到 lastIndex

基于 MIT 许可发布