跳转到内容

正则表达式基础入门教程 2026 | 零基础小白学 Regex

正则表达式基础入门教程

看到 /^[a-zA-Z0-9]+@[a-zA-Z0-9.]+$/ 这种像乱码一样的字符串就头大?别怕!正则表达式其实就是一种「描述文本模式的迷你语言」。这篇教程用大白话带你从零掌握它。


一、正则表达式是什么?

1.1 通俗理解

想象你是一个图书管理员,要在书架上找出「所有以开头、以结尾的三个字的人名」。你描述给助手听的就是一种「模式」。

正则表达式(Regular Expression,简称 Regex 或 RegExp)就是干这个的:用一串特殊符号描述「我要找什么样的文本」,然后计算机帮你把符合的都找出来。

1.2 能用来干什么?

场景例子
表单验证这个字符串是不是合法邮箱?手机号?
文本搜索在一篇文章里找出所有 URL 链接
文本替换把文章里所有「color」替换成「colour」
数据提取从日志里提取所有 IP 地址
字符串拆分按任意空白符分割句子

1.3 生活中的正则

  • 在 Word 里「查找替换」用通配符 ? *
  • 在终端用 ls *.md 列出所有 markdown 文件
  • 在 SQL 里用 LIKE '张%'

正则就是这些「通配符」的超级加强版。


二、在 JavaScript 里怎么用?

2.1 两种创建方式

javascript
// 方式一:字面量(推荐,简洁)
const re1 = /hello/g

// 方式二:构造函数(适合动态拼接)
const word = 'hello'
const re2 = new RegExp(word, 'g')

2.2 两个核心方法

javascript
// 1. test():判断字符串是否匹配(返回 true/false)
const re = /\d{4}/   // 匹配 4 位数字
console.log(re.test('订单号 2026'))   // true
console.log(re.test('没有数字'))       // false

// 2. match():取出匹配到的内容
const str = '我的手机是 13812345678,邮箱是 a@b.com'
console.log(str.match(/\d{11}/))   // ['13812345678']

2.3 常用方法速查

方法作用返回值
re.test(str)是否匹配true / false
str.match(re)提取匹配数组或 null
str.matchAll(re)提取所有匹配迭代器
str.replace(re, 新)替换新字符串
str.split(re)按模式分割数组
re.exec(str)详细匹配数组(含位置)

三、最基础:匹配普通字符

3.1 字面量匹配

最简单的正则,就是原样写你要找的字符:

javascript
const str = 'I love cats and cats are cute'

// 找出所有 'cats'
console.log(str.match(/cats/g))
// ['cats', 'cats']

注意结尾的 g

/cats/g 末尾的 g 是「全局匹配」标志,不加的话只找第一个。

3.2 标志位(Flags)

标志含义例子
g全局(找全部)/cat/g
i忽略大小写/cat/i 匹配 Cat CAT
m多行模式^ $ 匹配每行首尾
s. 匹配换行符跨行匹配

组合使用:/cat/gi = 全局 + 忽略大小写。


四、元字符:正则的「特殊符号」

元字符是正则里有特殊含义的符号,就像数学里的 + - × ÷

4.1 速查表

符号含义例子匹配
.任意一个字符(除换行)a.cabc a1c a@c
\d一个数字(0-9)\d\d42
\D非数字\Da @
\w字母数字下划线\w+hello_123
\W非字母数字下划线\W@ 空格
\s空白符(空格/制表/换行)\s
\S非空白符\Sa 1
\b单词边界\bcat\b匹配独立的 cat
\B非单词边界\Bcat匹配 concat 里的 cat

4.2 记忆技巧

  • 小写 = 「是这一类」(\d 是数字,\w 是字母数字,\s 是空白)
  • 大写 = 「不是这一类」(\D 非数字,\W 非字母数字,\S 非空白)

4.3 转义:想匹配符号本身

如果就想匹配 . * + 这些特殊符号本身,前面加 \

javascript
// 想匹配网址里的点
'www.google.com'.match(/\./g)   // ['.', '.']

// 想匹配价格里的美元符号
'$100'.match(/\$\d+/)   // ['$100']

需要转义的符号:. * + ? ^ $ { } [ ] \ | ( )


五、字符类:用方括号自定义范围

5.1 基本用法

[...] 表示「匹配其中任意一个字符」:

javascript
// 匹配 a、b、c 中任意一个
'banana'.match(/[abc]/g)   // ['b', 'a', 'a', 'a']

// 匹配一个数字
'a1b2'.match(/[0123456789]/g)   // ['1', '2']

5.2 范围表示法

- 表示范围:

javascript
/[a-z]/    // 任意小写字母
/[A-Z]/    // 任意大写字母
/[0-9]/    // 任意数字(等价于 \d)
/[a-zA-Z]/ // 任意字母
/[a-zA-Z0-9_]/  // 字母数字下划线(等价于 \w)

5.3 取反:[^...]

在开头加 ^ 表示「不要这些字符」:

javascript
// 匹配「非数字」
'abc123'.match(/[^0-9]/g)   // ['a', 'b', 'c']

// 匹配「非元音字母」
'hello'.match(/[^aeiou]/g)   // ['h', 'l', 'l']

注意区分

^[] 内是「取反」,在 [] 外是「行首」,含义完全不同!


六、量词:指定重复次数

6.1 速查表

量词含义例子匹配
*0 次或多次ab*cac abc abbc
+1 次或多次ab+cabc abbc(不匹配 ac
?0 次或 1 次colou?rcolor colour
{n}正好 n 次\d{4}2026
{n,}至少 n 次\d{2,}12 123 1234
{n,m}n 到 m 次\d{2,4}12 123 1234

6.2 实战例子

javascript
// 匹配手机号(11 位数字)
/^1\d{10}$/.test('13812345678')   // true

// 匹配 4-6 位验证码
/^\d{4,6}$/.test('123456')   // true

// 匹配 HTML 标签里的颜色(# 后 3 或 6 位)
'#fff'.match(/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/)   // 匹配

6.3 贪婪 vs 非贪婪

默认正则是「贪婪」的,会尽可能多匹配。加 ? 变「非贪婪」(尽可能少匹配):

javascript
const str = '<div>hello</div>'

// 贪婪(默认):匹配到最远的 >
str.match(/<.*>/)[0]   // '<div>hello</div>'

// 非贪婪:匹配到最近的 >
str.match(/<.*?>/)[0]  // '<div>'

记忆

量词后加 ? = 「别贪心,够了就行」。*? +? ?? {n,m}?


七、锚点:定位位置

7.1 三个常用锚点

符号含义例子
^字符串开头^Hello 匹配开头的 Hello
$字符串结尾world$ 匹配结尾的 world
\b单词边界\bcat\b 匹配独立的单词 cat

7.2 实战

javascript
// 必须是纯数字(从头到尾)
/^\d+$/.test('12345')    // true
/^\d+$/.test('12a45')    // false

// 以 https 开头
/^https:\/\//.test('https://example.com')   // true

// 匹配独立单词 'is',不匹配 'this' 里的 'is'
'this is a test'.match(/\bis\b/g)   // ['is']

表单验证必备

做表单验证时,记得用 ^$ 包住整个模式,否则只匹配到一部分也会返回 true:

  • /\d+/abc123 返回 true(因为里面有数字)
  • /^\d+$/abc123 返回 false(必须全是数字)

八、分组与引用

8.1 捕获分组 ()

用括号把一部分「打包」,可以整体应用量词或提取:

javascript
// 匹配 'ab' 重复 3 次
'ababab'.match(/(ab){3}/)   // 匹配

// 提取日期中的年月日
const date = '2026-08-08'
const m = date.match(/(\d{4})-(\d{2})-(\d{2})/)
console.log(m[1])  // '2026' 年
console.log(m[2])  // '08' 月
console.log(m[3])  // '08' 日

8.2 命名分组 (?<名字>)

javascript
const date = '2026-08-08'
const m = date.match(/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/)
console.log(m.groups.year)   // '2026'
console.log(m.groups.month)  // '08'

8.3 反向引用 \1

在正则里引用前面捕获到的内容:

javascript
// 匹配连续重复的单词
'hello hello world'.match(/\b(\w+)\s\1\b/)   // 匹配 'hello hello'

// 匹配成对的引号
'"hello"'.match(/(['"]).*?\1/)   // 匹配 '"hello"'(前后引号一致)

8.4 非捕获分组 (?:...)

括号默认会「捕获」内容(占内存),如果只想分组不捕获,加 ?:

javascript
// 只想整体应用 ? 量词,不需要提取
'color colour'.match(/colou(?:r|rs?)/g)

九、选择:或 |

| 表示「或」:

javascript
// 匹配 cat 或 dog
/cat|dog/.test('I have a dog')   // true

// 匹配几种水果
/apple|banana|orange/.test('banana')   // true

// 配合分组使用
/(jpg|png|gif)$/i.test('photo.JPG')   // true(图片后缀)

注意优先级

| 的优先级很低,cat|dog food 是「cat」或「dog food」。要「cat food 或 dog food」得写成 (cat|dog) food


十、常用正则大全(直接抄)

10.1 邮箱

javascript
const emailRe = /^[\w.+-]+@[\w-]+(\.[\w-]+)+$/

emailRe.test('user@example.com')        // true
emailRe.test('user.name+tag@site.co')   // true
emailRe.test('invalid')                  // false

10.2 手机号(中国大陆)

javascript
const phoneRe = /^1[3-9]\d{9}$/

phoneRe.test('13812345678')   // true
phoneRe.test('12345678901')   // false(第二位必须是 3-9)

10.3 URL

javascript
const urlRe = /^https?:\/\/[\w.-]+(\.[\w.-]+)+[/\w\-./?%&=]*$/

urlRe.test('https://www.example.com/path?q=1')   // true

10.4 身份证号(18 位)

javascript
const idRe = /^\d{17}[\dXx]$/

idRe.test('110105199001011234')   // true
idRe.test('11010519900101123X')   // true

10.5 IPv4 地址

javascript
const ipRe = /^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/

ipRe.test('192.168.1.1')    // true
ipRe.test('256.1.1.1')      // false

10.6 密码强度(至少 8 位,含大小写字母和数字)

javascript
const pwdRe = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/

pwdRe.test('Abc12345')   // true
pwdRe.test('abc12345')   // false(缺大写)
pwdRe.test('Abc1')       // false(太短)

零宽断言

(?=...) 叫「正向先行断言」,表示「后面要跟着...」但不消耗字符。上面密码正则用三个断言确保「整个字符串里既有大写、又有小写、又有数字」。

10.7 中文字符

javascript
const cnRe = /[\u4e00-\u9fa5]+/

cnRe.test('你好world')   // true
'你好world'.match(cnRe)   // ['你好']

10.8 提取网页所有链接

javascript
const html = '<a href="https://a.com">A</a> <a href="/b">B</a>'
const urls = html.match(/href="([^"]+)"/g)
// ['href="https://a.com"', 'href="/b"']

十一、在表单验证中实战

11.1 一个完整的表单校验

html
<form id="myForm">
  <div>
    <label>邮箱</label>
    <input type="text" id="email">
    <span class="error" id="emailErr"></span>
  </div>
  <div>
    <label>手机号</label>
    <input type="text" id="phone">
    <span class="error" id="phoneErr"></span>
  </div>
  <div>
    <label>密码(8位以上含大小写和数字)</label>
    <input type="password" id="pwd">
    <span class="error" id="pwdErr"></span>
  </div>
  <button type="submit">提交</button>
</form>

<script>
const rules = {
  email: /^[\w.+-]+@[\w-]+(\.[\w-]+)+$/,
  phone: /^1[3-9]\d{9}$/,
  pwd: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/
}

const msgs = {
  email: '邮箱格式不正确',
  phone: '手机号格式不正确',
  pwd: '密码需 8 位以上,含大小写字母和数字'
}

document.getElementById('myForm').addEventListener('submit', (e) => {
  e.preventDefault()
  let valid = true
  
  for (const field of ['email', 'phone', 'pwd']) {
    const value = document.getElementById(field).value
    const errEl = document.getElementById(field + 'Err')
    if (!rules[field].test(value)) {
      errEl.textContent = msgs[field]
      valid = false
    } else {
      errEl.textContent = ''
    }
  }
  
  if (valid) {
    alert('提交成功!')
  }
})
</script>

11.2 文本替换实战

javascript
// 把手机号中间 4 位替换成 ****
'13812345678'.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
// '138****5678'

// 把文本里的 URL 变成链接
const text = '访问 https://example.com 看看'
text.replace(/(https?:\/\/[^\s]+)/g, '<a href="$1">$1</a>')
// '访问 <a href="https://example.com">https://example.com</a> 看看'

// 驼峰转下划线
'userName'.replace(/([A-Z])/g, '_$1').toLowerCase()
// 'user_name'

十二、调试技巧

12.1 在线工具推荐

12.2 浏览器里直接试

打开浏览器控制台(F12),直接敲:

javascript
/^\d{4}$/.test('2026')   // true

12.3 调试步骤

  1. 先把要匹配的样本数据列出来
  2. 在 regex101 里粘贴样本
  3. 逐步写正则,每写一段看高亮是否正确
  4. 加入边界测试(该匹配的、不该匹配的都试)
  5. 复制到代码里使用

12.4 常见调试坑

javascript
// 坑:忘了 ^ $,部分匹配也算对
/\d{11}/.test('abc13812345678xyz')  // true(里面有 11 位数字)
/^\d{11}$/.test('abc13812345678xyz') // false(必须是纯 11 位)

// 坑:忘了 g 标志,replace 只换第一个
'aabb'.replace(/a/, 'X')    // 'Xabb'
'aabb'.replace(/a/g, 'X')   // 'XXbb'

十三、练习题

基础题

  1. 写一个正则,匹配任意 3 位数字 → /\d{3}/
  2. 写一个正则,匹配以 http 开头的字符串 → /^http/
  3. 写一个正则,匹配包含「cat」或「dog」的句子 → /cat|dog/

进阶题

  1. 写一个正则,匹配 6-16 位由字母和数字组成的密码
  2. 写一个正则,提取字符串里所有的邮箱地址
  3. 写一个正则,把日期 2026/08/08 转成 2026-08-08

参考答案

javascript
// 题 4
/^[a-zA-Z0-9]{6,16}$/

// 题 5
const text = '联系 a@b.com 或 c@d.com'
text.match(/[\w.+-]+@[\w-]+(\.[\w-]+)+/g)
// ['a@b.com', 'c@d.com']

// 题 6
'2026/08/08'.replace(/\//g, '-')   // '2026-08-08'

十四、正则速查卡(收藏)

基础:
  .        任意字符
  \d \D    数字 / 非数字
  \w \W    字母数字下划线 / 非字母数字下划线
  \s \S    空白 / 非空白
  \b \B    单词边界 / 非边界

字符类:
  [abc]    a 或 b 或 c
  [a-z]    a 到 z
  [^abc]   非 a、b、c

量词:
  *        0 次或多次
  +        1 次或多次
  ?        0 次或 1 次
  {n}      正好 n 次
  {n,}     至少 n 次
  {n,m}    n 到 m 次
  *? +? ?? 非贪婪版本

锚点:
  ^        开头
  $        结尾

分组:
  (...)        捕获分组
  (?:...)      非捕获分组
  (?<name>...) 命名分组
  \1 \2        反向引用

选择:
  |        或

标志:
  g        全局
  i        忽略大小写
  m        多行
  s        . 匹配换行

零宽断言:
  (?=...)    后面跟着
  (?!...)    后面不跟着
  (?<=...)   前面是
  (?<!...)   前面不是

总结

正则表达式的学习路线:

  1. 认识工具:知道 test() match() replace() 怎么用
  2. 掌握元字符. \d \w \s \b 这些基础符号
  3. 学会量词* + ? {n,m} 控制重复
  4. 会用字符类[a-z] [^0-9] 自定义范围
  5. 理解分组() 打包、提取、引用
  6. 记常用模板:邮箱、手机号、URL 这些直接抄
  7. 多练多查:用 regex101 边写边测

学习建议

不用死记硬背!记住「正则能干什么」,具体语法用的时候查速查卡就行。写多了自然就熟了。

正则是程序员的「瑞士军刀」,虽然看起来像乱码,但掌握后你会发现它无比强大。遇到文本处理问题,第一反应就会变成:「这个能用正则解决吗?」

下一步建议结合 JavaScript 基础入门教程 里的字符串处理章节一起练习,效果更好。