Abstract

这篇笔记只整理“绝大部分开发里常用的正则表达式知识”。 目标不是覆盖所有冷门语法,而是让你能看懂、会写、会改常见正则。

一句话理解正则表达式

正则表达式,就是一种描述字符串模式的规则。

你可以用它来做这些事:

  1. 判断一段字符串是否符合某种格式。
  2. 从一段字符串中提取某些部分。
  3. 把匹配到的内容替换掉。
  4. 按某种规则拆分字符串。

JavaScript 里,它经常配合这些方法一起出现:

  • test()
  • exec()
  • match()
  • matchAll()
  • replace()
  • split()
  • search()

二、最常见的写法

正则通常有两种写法:

/abc/
 
new RegExp("abc")

日常开发里更常见的是第一种字面量写法。

例如:

/hello/

表示:匹配字符串里是否出现 hello

三、最常用的基础语法

1. 普通字符

普通字符就表示它自己。

/abc/

表示匹配 abc

2. 字符类 []

表示“匹配方括号中的任意一个字符”。

/[abc]/

表示匹配:

  • a
  • b
  • c

例如:

/[abc]/.test("cat") // true

常见写法

/[0-9]/      // 任意一位数字
/[a-z]/      // 任意一个小写字母
/[A-Z]/      // 任意一个大写字母
/[a-zA-Z]/   // 任意一个英文字母
/[a-zA-Z0-9]/ // 任意一个字母或数字

3. 取反字符类 [^]

在方括号里,^ 放在最前面时,表示“不要这些字符”。

/[^0-9]/

表示匹配任意一个“非数字”字符。

4. 预定义字符类

这是最常用的一组缩写。

写法含义
\d任意一个数字,等价于 [0-9]
\D任意一个非数字
\w任意一个字母、数字、下划线,约等于 [A-Za-z0-9_]
\W任意一个非“字母数字下划线”字符
\s任意一个空白字符,如空格、换行、制表符
\S任意一个非空白字符
.任意一个字符,通常不包含换行

例子:

/\d\d/.test("12") // true
/\w+/.test("hello_123") // true
/\s/.test("a b") // true

Tip

. 很常用,但也最容易误伤。 它表示“几乎任意字符”,所以写宽了很容易匹配过头。

四、量词:匹配多少次

量词是正则里非常核心的一部分。

1. 常见量词

写法含义
*前面的内容出现 0 次或多次
+前面的内容出现 1 次或多次
?前面的内容出现 0 次或 1 次
{n}前面的内容恰好出现 n 次
{n,}前面的内容至少出现 n 次
{n,m}前面的内容出现 n 到 m 次

例子:

/a*/     // "", "a", "aa", "aaa"
/a+/     // "a", "aa", "aaa"
/a?/     // "", "a"
/\d{3}/  // 恰好 3 位数字
/\d{6,}/ // 至少 6 位数字

2. 贪婪模式与非贪婪模式

默认情况下,量词是贪婪的,也就是“能吃多少吃多少”。

/".+"/

这种思路会尽可能多地匹配。

更常见的写法是加 ? 变成非贪婪:

/".+?"/

例子:

const str = 'a "one" b "two"'
 
str.match(/".+"/)   // 可能吃到 "one" b "two"
str.match(/".+?"/)  // 只匹配到 "one"

Warning

很多“正则匹配太多了”的问题,本质就是贪婪匹配导致的。

五、边界:匹配在什么位置

边界不匹配字符本身,而是匹配“位置”。

1. 开头和结尾

写法含义
^字符串开头
$字符串结尾

例子:

/^abc/   // 以 abc 开头
/abc$/   // 以 abc 结尾
/^abc$/  // 整个字符串必须就是 abc

这组非常重要。

比如你想验证“整个输入是否为 11 位数字”,就不能只写:

/\d{11}/

因为这只是“字符串里出现了 11 位数字”。

而更准确的是:

/^\d{11}$/

表示整段字符串从头到尾都必须是 11 位数字。

2. 单词边界

写法含义
\b单词边界
\B非单词边界

例如:

/\bcat\b/

表示匹配独立的 cat,而不是 catalog 里的 cat

六、分组与或

1. 分组 ()

圆括号有两个最常见用途:

  1. 把多个内容当成一个整体。
  2. 捕获匹配到的内容。

例如:

/(ab)+/

表示 ab 这个整体出现一次或多次。

2. 或 |

表示“二选一”。

/cat|dog/

表示匹配 catdog

如果要和分组配合:

/gr(a|e)y/

表示匹配:

  • gray
  • grey

3. 捕获组

括号默认会捕获内容。

/(\d{4})-(\d{2})-(\d{2})/

如果匹配 2026-05-07,就能把年、月、日分别抓出来。

const result = "2026-05-07".match(/(\d{4})-(\d{2})-(\d{2})/)

常见结果:

  • 第 0 项:完整匹配
  • 第 1 项:第一组
  • 第 2 项:第二组
  • 第 3 项:第三组

4. 非捕获组 (?:)

如果你只想分组,不想捕获,可以用:

/(?:ab)+/

这在结构复杂一点的正则里很有用。

七、常用断言

断言的特点是:它只判断位置条件,不真正消费字符。

日常最常用的是下面四种。

1. 正向先行断言 (?=...)

表示:后面必须跟着某内容。

/\d(?=px)/

表示匹配后面紧跟 px 的数字。

例如在 12px 中,可以匹配到 2 这个位置上的数字。

2. 负向先行断言 (?!...)

表示:后面不能跟着某内容。

/\d(?!px)/

3. 正向后行断言 (?<=...)

表示:前面必须是某内容。

/(?<=\$)\d+/

表示匹配 $100 里的 100

4. 负向后行断言 (?<!...)

表示:前面不能是某内容。

/(?<!\$)\d+/

Note

断言在“提取某一部分内容,但不想把前后标记也带上”时特别好用。

八、常用修饰符

修饰符写在正则最后面。

/abc/g

最常用的是这些:

修饰符含义
g全局匹配
i忽略大小写
m多行模式
s. 也能匹配换行

1. g

如果不加 g,通常只拿到第一个匹配。

"a1b2c3".match(/\d/)  // 只拿第一个
"a1b2c3".match(/\d/g) // 拿到全部

2. i

忽略大小写。

/abc/i

可以匹配 abcABCAbc

3. m

^$ 针对每一行生效,而不是只针对整个字符串的头尾。

4. s

. 能匹配换行。

这个在处理多行文本时很有用。

九、转义:什么时候要加反斜杠

有些字符在正则里有特殊含义,如果你想匹配它本身,就要转义。

常见需要转义的字符有:

. * + ? ^ $ { } ( ) [ ] \ | /

例如匹配点号 .

/\./

匹配左括号:

/\(/

匹配网址里的 https:// 时,也常常会遇到转义问题。

十、JavaScript 里最常用的几个方法

1. test()

只关心“符不符合”时最常用。

/^\d+$/.test("123") // true

2. exec()

适合拿更详细的匹配结果。

/\d+/.exec("abc123def")

3. match()

字符串方法。

"abc123def".match(/\d+/)

4. replace()

特别常用。

"2026-05-07".replace(/-/g, "/")

5. split()

按某个模式拆分字符串。

"a, b; c".split(/[;,]\s*/)

十一、最常见的实战例子

这里只放最常用、最有代表性的。

1. 匹配纯数字

/^\d+$/

2. 匹配字母和数字

/^[A-Za-z0-9]+$/

3. 匹配字母、数字、下划线

/^\w+$/

4. 匹配 6 到 18 位密码

/^[A-Za-z0-9_]{6,18}$/

5. 匹配 11 位手机号(简单版)

/^1\d{10}$/

Warning

像手机号、邮箱这类格式,正则通常只能做“基本校验”。 真正严谨的业务校验,往往还需要额外规则。

6. 匹配邮箱(常用简化版)

/^[^\s@]+@[^\s@]+\.[^\s@]+$/

7. 匹配 URL(简单版)

/^https?:\/\/[^\s/$.?#].[^\s]*$/i

这个可以和 URL 一起理解。

8. 提取日期

/(\d{4})-(\d{2})-(\d{2})/

适合提取这种格式:

2026-05-07

9. 去掉首尾空格

/^\s+|\s+$/g

当然在 JavaScript 里更推荐直接用:

str.trim()

10. 把多个空白合成一个空格

/\s+/g

11. 提取标签内容时的基础思路

/<[^>]+>/

但这里一定要注意:

Danger

不要把正则当成完整解析 HTML 的工具。 处理 HTML 结构,更应该使用 DOM 或解析器。

十二、写正则时的实用思路

如果你觉得正则难写,通常不是语法问题,而是没有拆解问题。

更好的写法是:

  1. 先确认要匹配的是“整段”,还是“其中一部分”。
  2. 再确认是否需要 ^$
  3. 再拆成一个个小块。
  4. 最后再加量词、分组、断言。

比如“11 位手机号”可以拆成:

  1. 整段都要匹配,所以加 ^$
  2. 第一位必须是 1
  3. 后面再跟 10 位数字

最后得到:

/^1\d{10}$/

十三、初学者最容易犯的错

1. 忘了加 ^$

这是最常见的问题之一。

/\d{6}/

/^\d{6}$/

含义完全不同。

前者表示“包含 6 位数字”,后者表示“整个字符串就是 6 位数字”。

2. . 用太多

/.+/

很容易写得过宽。

3. 贪婪匹配导致吃太多

尤其是在配合 .*.+ 时最常见。

4. 过度追求“一条正则解决一切”

很多时候,把逻辑拆成两步写,会比一条超复杂正则更清晰、更可维护。

十四、够用的学习顺序

如果你只想掌握大部分常用正则,建议按这个顺序:

  1. 普通字符
  2. 字符类 []
  3. 预定义字符类 \d \w \s
  4. 量词 * + ? {n,m}
  5. 边界 ^ $
  6. 分组 ()|
  7. 常见方法 test / match / replace
  8. 断言

把这些学会,已经能覆盖大多数日常开发场景。

十五、最值得记住的几个模板

/^\d+$/                      // 纯数字
/^[A-Za-z]+$/               // 纯字母
/^\w+$/                      // 字母数字下划线
/^\d{4}-\d{2}-\d{2}$/       // 日期 yyyy-mm-dd
/^1\d{10}$/                 // 中国大陆手机号简化版
/^[^\s@]+@[^\s@]+\.[^\s@]+$/ // 邮箱简化版
/\s+/g                      // 连续空白
/^\s+|\s+$/g                // 首尾空白

相关笔记