正则表达式实战指南:从手机号验证到模板引擎,5 个案例彻底搞懂 RegExp

正则表达式实战指南:从手机号验证到模板引擎,5 个案例彻底搞懂 RegExp

正则表达式是前端面试的高频考点,也是实际开发中处理字符串的利器。这篇文章通过 5 个真实案例,带你从零掌握正则的核心语法。

前言

今天课程从一道拼多多笔试题出发,系统学习了 JavaScript 正则表达式(RegExp)。

从手机号验证到字符串提取,从驼峰命名转换到简易模板引擎------每个案例都对应正则的一个核心用法。这篇文章将完整复盘学习过程。


一、正则表达式是什么?

1.1 一句话理解

正则表达式(Regular Expression)是一种描述字符串匹配规则的工具。它用一种特殊的语法,精确地定义"我要找什么样的字符串"。

1.2 核心语法速查

scss 复制代码
正则表达式核心语法

/  /          ← 正则的字面量写法
[]            ← 字符范围,匹配括号内的任意一个字符
\d            ← 数字(等价于 [0-9])
\w            ← 字母/数字/下划线(等价于 [a-zA-Z0-9_])
{}            ← 匹配次数
^             ← 以什么开头
$             ← 以什么结尾
g             ← 全局匹配修饰符
()            ← 分组(捕获)
$1            ← 引用第 1 个分组

1.3 JS 中的正则类型

javascript 复制代码
console.log(typeof /abc/);  // "object"
console.log(typeof {});     // "object"

// 如何区分正则和普通对象?
console.log(
    Object.prototype.toString.call(/abc/)
);  // "[object RegExp]"

💡 typeof 无法区分正则和普通对象(都是 object),需要用 Object.prototype.toString.call() 来精确判断。


二、案例一:手机号验证(拼多多笔试题)

2.1 需求分析

验证用户输入的手机号是否合法:

规则 说明
11 位数字 手机号固定 11 位
以 1 开头 中国手机号首位固定为 1
第二位 3-9 第二位不能为 0、1、2
后 9 位数字 剩余 9 位为任意数字

2.2 正则拆解

javascript 复制代码
const reg = /^1[3-9]\d{9}$/;
css 复制代码
正则逐字符解析

/^1[3-9]\d{9}$/
 │ │  │  │  │ │
 │ │  │  │  │ └── $ 字符串结尾(精确匹配)
 │ │  │  │  └─── {9} 前面的 \d 重复 9 次
 │ │  │  └────── \d 任意数字 [0-9]
 │ │  └───────── [3-9] 第二位 3 到 9
 │ └──────────── 1 第一位固定为 1
 └─────────────── ^ 字符串开头(精确匹配)

2.3 完整代码

javascript 复制代码
let str = '13888888888';
let reg = /^1[3-9]\d{9}$/;

console.log(reg.test(str));  // true

reg.test('12345678901');  // false(第二位是 2)
reg.test('1388888888');   // false(只有 10 位)
reg.test('23888888888');  // false(不以 1 开头)

🎯 永远不要相信用户的输入------把用户当小白,所有输入都要验证。


三、案例二:提取字符串中的数字

3.1 需求

从一段文本中提取所有数字。

3.2 核心语法:match + g 全局匹配

javascript 复制代码
const str = '价格是100元,进价是90元,赚了10元';
const reg = /\d+/g;
const res = str.match(reg);
console.log(res);  // ['100', '90', '10']
bash 复制代码
正则解析

/\d+/g
 │  │ └── g 全局匹配(不找到第一个就停,找所有)
 │  └─── + 匹配一次或多次(贪婪模式,尽可能多匹配)
 └────── \d 匹配任意数字

匹配过程:
'价格是100元,进价是90元,赚了10元'
         ^^^         ^^^        ^^
        100         90         10

3.3 match vs test

方法 返回值 用途
reg.test(str) true / false 判断是否匹配
str.match(reg) 匹配结果的数组 提取匹配内容

💡 + 量词\d 只匹配一个数字,\d+ 匹配一个或多个数字。+ 是贪婪模式,会尽可能多地匹配。


四、案例三:字符串替换(驼峰命名转换)

4.1 需求

hello-world 转换为 helloWorld(短横线命名 → 小驼峰命名)。

4.2 核心语法:replace + () 分组

javascript 复制代码
const str = 'hello-world';
const reg = /-(\w)/;

// match 查看分组捕获
console.log(str.match(reg));
// ['h-w', 'w', index: 5, ...]
//  ↑     ↑
//  完整匹配  第1个分组(括号内的内容)

4.3 分组(Group)详解

scss 复制代码
/-(\w)/
 │  │
 │  └── (\w) 分组:用括号包裹,捕获匹配的内容
 └───── - 匹配连字符

match 返回值结构:
['-w', 'w', index: 5, input: 'hello-world']
  ↑     ↑
  完整  第1个分组($1)
  匹配  括号内的内容

4.4 replace 的回调函数

javascript 复制代码
const str = 'hello-world';
const reg = /-(\w)/;

const res = str.replace(reg, (_, c) => {
    console.log(_, c);  // '-w'  'w'
    // _ = 完整匹配  c = 第1个分组
    return c.toUpperCase();
});

console.log(res);  // 'helloWorld'
javascript 复制代码
replace 回调函数参数

str.replace(reg, (完整匹配, 分组1, 分组2, ..., 偏移量, 原字符串) => {
    // 完整匹配 = _(通常用 _ 表示不使用)
    // 分组1 = $1
    // 偏移量 = 匹配在原字符串中的位置
    // 原字符串 = 原始输入
});

4.5 多个连字符的处理

javascript 复制代码
// 只替换了第一个 -w
'hello-world'.replace(/-(\w)/, (_, c) => c.toUpperCase())
// 'helloWorld' ✅

// 如果有多个连字符?
'hello-my-world'.replace(/-(\w)/, (_, c) => c.toUpperCase())
// 'helloMy-world' ❌ 只替换了第一个!

📌 注意 :不加 g 修饰符,replace 只替换第一个匹配。要替换所有匹配,需要加 g


五、案例四:replace 回调函数深入理解

5.1 回调函数的参数结构

javascript 复制代码
"hello-world".replace(
    /-(\w)/,
    (...args) => {
        console.log(args);
        // args[0] = '-w'     完整匹配
        // args[1] = 'w'      第1个分组
        // args[2] = 5        匹配位置的偏移量
        // args[3] = 'hello-world'  原始字符串
        return '';
    }
);

5.2 参数对照表

参数位置 含义 示例值
args[0] / _ 完整匹配的子串 '-w'
args[1] / $1 第 1 个分组 'w'
args[2] / $2 第 2 个分组(如有) ---
args[n-2] 偏移量(匹配位置) 5
args[n-1] 原始字符串 'hello-world'

💡 _ 是约定俗成的写法,表示"这个参数我不关心,用下划线占位"。这是 JS 开发中的常见惯例。


六、案例五:简易模板引擎(递归 + 正则)

6.1 需求

实现一个简易模板引擎,将 {{name}} 替换为实际数据。

javascript 复制代码
let template = `我是{{name}},今年{{age}}岁,性别{{sex}}`;
let person = {
    name: '张三',
    age: 18,
    sex: '男'
};

6.2 核心思路

kotlin 复制代码
模板引擎工作流程

"我是{{name}},今年{{age}}岁"
         │
         ▼
找到第一个 {{name}}
         │
         ▼
替换为 data['name'] → '张三'
         │
         ▼
"我是张三,今年{{age}}岁"
         │
         ▼
找到下一个 {{age}}
         │
         ▼
替换为 data['age'] → 18
         │
         ▼
"我是张三,今年18岁,性别{{sex}}"
         │
         ▼
... 递归直到没有 {{}} 为止

6.3 完整代码

javascript 复制代码
let template = `我是{{name}},今年{{age}}岁,性别{{sex}}`;
let person = {
    name: '张三',
    age: 18,
    sex: '男'
};

function render(template, data) {
    // {} 在正则中有特殊含义,需要转义为 \{\{
    const reg = /\{\{(\w+)\}\}/;
    
    if (reg.test(template)) {
        // exec 返回匹配结果数组,[1] 是第一个分组
        const name = reg.exec(template)[1];
        // 用 data 中的值替换模板变量
        template = template.replace(reg, data[name]);
        // 递归:继续处理下一个 {{}}
        return render(template, data);
    }
    
    return template;
}

console.log(render(template, person));
// "我是张三,今年18岁,性别男"

6.4 正则拆解

scss 复制代码
/\{\{(\w+)\}\}/
 │  │  │  │ │
 │  │  │  │ └── } 匹配右花括号
 │  │  │  └─── \} 转义的右花括号
 │  │  └────── (\w+) 分组:捕获变量名
 │  └───────── \{ 转义的左花括号
 └──────────── \{ 匹配左花括号

为什么需要转义?
{} 在正则中表示"匹配次数",如 \d{3}
要匹配字面量的 {,需要写 \{

6.5 exec vs match

方法 调用者 返回值
reg.exec(str) 正则对象 匹配详情数组(含分组)
str.match(reg) 字符串对象 匹配结果数组
javascript 复制代码
const reg = /\{\{(\w+)\}\}/;
const template = '我是{{name}}';

reg.exec(template);
// ['{{name}}', 'name', index: 2, input: '我是{{name}}']
//  ↑ 完整匹配    ↑ 分组1

template.match(reg);
// ['{{name}}', 'name', index: 2, input: '我是{{name}}']
// 结果相同(无 g 修饰符时)

🎯 这个简易模板引擎的原理,就是 Vue、React 等框架模板编译的基础思想!


七、JS 数据类型补充

7.1 两大类型阵营

javascript 复制代码
JS 数据类型

基本类型(值类型)
├── Number    数值
├── String    字符串
├── Boolean   布尔值
├── Null      空值
└── Undefined 未定义

引用类型(对象类型)
├── Object    普通对象
├── Array     数组
├── Function  函数
├── Date      日期
├── RegExp    正则表达式 ← 今天的主角
├── Error     错误对象
├── Math      数学对象
└── JSON      JSON 对象

💡 RegExp 是引用类型typeof 返回 object。它是 JS 中专门处理字符串模式匹配的对象。


八、知识图谱

scss 复制代码
📚 正则表达式知识图谱

核心语法
├── /  /          字面量
├── []            字符范围
├── \d            数字
├── \w            字母/数字/下划线
├── {}            匹配次数
├── ^ / $         开头 / 结尾
├── g             全局匹配修饰符
├── ()            分组捕获
└── $1            引用分组

JS 正则方法
├── reg.test(str)      是否匹配 → boolean
├── str.match(reg)    提取匹配 → 数组
├── str.replace(reg, fn)  替换匹配 → 新字符串
└── reg.exec(str)     匹配详情 → 数组

实战案例
├── 手机号验证
│   └── /^1[3-9]\d{9}$/
├── 提取数字
│   └── /\d+/g + match
├── 驼峰命名转换
│   └── /-(\w)/ + replace 回调
└── 简易模板引擎
    └── /\{\{(\w+)\}\}/ + 递归

关键概念
├── 分组 ():捕获匹配内容
├── $1:引用第 1 个分组
├── g 修饰符:全局匹配
├── + 量词:一次或多次
├── 转义 \{:匹配字面量 {
└── 递归:重复处理直到无匹配

九、正则速查表

语法 含义 示例
. 任意字符(除换行) /a.c/abc
\d 数字 [0-9] /\d+/123
\w 字母/数字/下划线 /\w+/hello
\s 空白字符 /\s+/
^ 开头 /^hello/
$ 结尾 /world$/
* 0 次或多次 /ab*c/ac
+ 1 次或多次 /ab+c/abc
? 0 次或 1 次 /colou?r/color
{n} 恰好 n 次 /\d{4}/2024
{n,m} n 到 m 次 /\d{1,3}/42
[] 字符范围 /[a-z]/a
() 分组捕获 /(ab)/
` `
g 全局匹配 /\d+/g

结语

正则表达式看似"天书",但掌握了核心语法后,你会发现它处理字符串的能力非常强大。

今天的 5 个案例覆盖了正则最常用的场景:

  1. 验证test() + ^ $ 精确匹配
  2. 提取match() + g 全局匹配
  3. 替换replace() + () 分组
  4. 回调replace(fn) + $1 引用
  5. 递归exec() + 递归函数

记住:正则不是背出来的,是用出来的。遇到字符串处理的需求,先想想能不能用正则解决。

希望这篇文章对你有帮助!如果有任何问题,欢迎在评论区交流。


📌 参考资源


📌 文章标签 JavaScript 正则表达式 RegExp 前端面试 字符串处理 学习笔记


觉得有收获?点个赞鼓励一下吧!有问题欢迎评论区留言~ 👍

相关推荐
sugar__salt1 小时前
JS正则表达式与字符串高阶实战精讲
开发语言·javascript·正则表达式
HjhIron1 小时前
从手机号校验到模板引擎:正则表达式的实战之旅
javascript
Hello馒头儿1 小时前
vue3+uniapp经典hook方式实现一个更多加载的列表组件
前端·javascript·vue.js
用户938515635071 小时前
前端必会:从 Fetch 到 DeepSeek,一篇搞懂 HTTP 请求的方方面面
javascript·架构
海梨花1 小时前
腾讯面试高频算法题
java·算法·面试
半个烧饼不加肉1 小时前
JS 底层探究--执行上下文
开发语言·前端·javascript
山河木马2 小时前
无框架-原生webGL渲染-底层入门-1
前端·javascript·webgl
郝学胜_神的一滴2 小时前
系统设计 014:缓存深度实战:如何用 Cache 优雅优化数据库读写?
前端·后端·面试