前言
前期 , 看到团内多个学长冲击大厂的面试题有关正则表达式 , 趁着春节下午休闲 , 搞一搞 ~
📅 安排如下:
- 先进行基础学习 , 学习正则的规律
- 之后开始写题目 , 巩固强化训练
- 最后直接面试🤡
- 腾讯校招笔试题
- 百度面试题
基础学习
正则表达式(Regular Expression,简称 Regex)就像“文字查找和替换的高级工具”,通过简单的符号规则,快速匹配、查找、替换复杂的文本。以下是小白也能快速记住的核心规则,用 符号 + 例子 + 口诀 帮你理解!
🧠 正则表达式(Regular Expression,简称 Regex)就像“文字查找和替换的高级工具”,通过简单的符号规则,快速匹配、查找、替换复杂的文本。以下是小白也能快速记住的核心规则,用 符号 + 例子 + 口诀 帮你理解!
🔍 配合例子快速过一遍正则表达式,我要匹配一个字符串,需要搞懂:
- 匹配字符串中的谁?
- 匹配这个“谁”或这些“谁”多少次?
- 在字符串中哪里匹配?
之后则是一些特殊处理:
- 分组与逻辑
- 转义字符
- 全局匹配否?
一、基础符号:匹配“谁”
符号 | 作用 | 例子 | 口诀 |
---|---|---|---|
abc | 匹配具体字符 abc | "a" → 匹配 a | 字面匹配 |
. | 匹配任意一个字符 | "a.c" → abc /a1c | 点代表任意 |
\d | 匹配数字(0-9) | \d → 0 /5 | d 是 digit |
\w | 匹配字母、数字、下划线 | \w → a /3 /_ | w 是 word字符 |
\s | 匹配空白符(空格、换行等) | \s → 空格 | s 是 space |
[abc] | 匹配括号中任意一个字符 | [ae] → a /e | 中括号里选一个 |
[^abc] | 匹配不在括号中的字符 | [^ae] → b /3 | ^ 是取反 |
[a-z] | 匹配范围内的字符 | [0-9] → 数字 | 连字符表范围 |
二、量词:匹配“多少次”
符号 | 作用 | 例子 | 口诀 |
---|---|---|---|
* | 匹配0次或多次 | a* → "" /a /aaaa | 星号是零或多 |
+ | 匹配1次或多次 | a+ → a /aaa (不能空) | 加号至少一次 |
? | 匹配0次或1次 | a? → "" /a | 问号可有可无 |
{n} | 匹配恰好n次 | a{3} → aaa | 花括号精确次数 |
{n,} | 匹配至少n次 | a{2,} → aa /aaaa | 逗号表下限 |
{n,m} | 匹配n到m次 | a{2,4} → aa /aaaa | 逗号分隔范围 |
三、位置:匹配“在哪里”
符号 | 作用 | 例子 | 口诀 |
---|---|---|---|
^ | 匹配字符串开头 | ^a → 开头的 a | ^ 是开头 |
$ | 匹配字符串结尾 | a$ → 结尾的 a | $ 是结尾 |
\b | 匹配单词边界 | \bcat\b → 匹配单词 cat | b 是边界 |
四、分组与逻辑
符号 | 作用 | 例子 | 口诀 |
---|---|---|---|
(abc) | 分组,后续可引用 | (ab)+ → abab | 括号分组 |
` | ` | 逻辑或 | `a |
五、转义符:匹配特殊符号
符号 | 作用 | 例子 | 口诀 |
---|---|---|---|
\ | 转义符号本身(如 . 、* ) | \. → 匹配 . | 反斜杠转义 |
六、标志(Flags):全局匹配模式
标志 | 作用 | 例子 | 口诀 |
---|---|---|---|
g | 全局匹配(所有结果) | /a/g → 所有 a | g 是 global |
i | 忽略大小写 | /a/i → A /a | i 是 ignore case |
七、快速记忆口诀🚀🚀🚀
.
任意,\d
数字,\w
字,\s
空。[]
选一个,^
开头$
结尾。*
零或多,+
一或多,?
零或一。{}
次数定,|
是或,()
分组用。\
要转义,g
全局i
不区分。
八、实战例子
- 匹配手机号:
/^1[3-9]\d{9}$/
- 以
1
开头,第二位是3-9
,后面接9位数字。
- 以
- 删除所有空格:
s.replace(/\s/g, '')
- 匹配邮箱:
/\w+@\w+\.[a-z]+/i
九 实际开发手段
- 多用在线工具(如 Regex101),实时测试表达式。
- 从简单需求开始(如查找数字),逐步增加复杂度。
- 记住常见规则,其他查文档即可!
正则表达式看似复杂,但掌握核心符号后,就能轻松应对大部分需求! 🚀
实战
以下是关于正则表达式的常见面试题,涵盖基础、进阶和实战应用,巩固知识并应对面试!
一、基础题
- 什么是正则表达式?它的作用是什么?
- 提示:正则表达式是一种用于匹配、查找和替换文本的工具,常用于验证输入、提取数据等。
- 如何匹配一个数字?
- 答案:
\d
或[0-9]
。
- 答案:
- 如何匹配一个非数字字符?
- 答案:
\D
或[^0-9]
。
- 答案:
- 如何匹配一个单词字符(字母、数字、下划线)?
- 答案:
\w
。
- 答案:
- 如何匹配空白字符(空格、换行、制表符等)?
- 答案:
\s
。
- 答案:
- 如何匹配任意字符?
- 答案:
.
。
- 答案:
- 如何匹配字符串的开头和结尾?
- 答案:
^
匹配开头,$
匹配结尾。
- 答案:
二、进阶题
- 如何匹配一个邮箱地址?
- 答案:
/\w+@\w+\.[a-z]+/i
(简单版)。
- 答案:
- 如何匹配一个手机号(中国大陆)?
- 答案:
/^1[3-9]\d{9}$/
。
- 答案:
- 如何匹配一个 URL?
- 答案:
/https?:\/\/[\w\-\.]+(\/[\w\-\.]*)*/i
。
- 答案:
- 如何匹配一个 HTML 标签?
- 答案:
/<[^>]+>/
。
- 答案:
- 如何匹配一个日期(格式:YYYY-MM-DD)?
- 答案:
/\d{4}-\d{2}-\d{2}/
。
- 答案:
- 如何匹配一个 IP 地址?
- 答案:
/(\d{1,3}\.){3}\d{1,3}/
。
- 答案:
- 如何匹配一个十六进制颜色值(如
#FFFFFF
)?- 答案:
/#[0-9a-fA-F]{6}/
。
- 答案:
三、实战题
- 写一个正则表达式,删除字符串中的所有空格。
- 答案:
s.replace(/\s/g, '')
。
- 答案:
- 写一个正则表达式,提取字符串中的所有数字。
- 答案:
s.match(/\d+/g)
。
- 答案:
- 写一个正则表达式,验证密码强度(至少8位,包含大小写字母和数字)。
- 答案:
/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$/
。
- 答案:
- 写一个正则表达式,匹配所有以
ing
结尾的单词。- 答案:
/\b\w+ing\b/g
。
- 答案:
- 写一个正则表达式,匹配所有以
http
或https
开头的 URL。- 答案:
/^https?:\/\/\S+/
。
- 答案:
- 写一个正则表达式,匹配所有中文汉字。
- 答案:
/[\u4e00-\u9fa5]/
。
- 答案:
- 写一个正则表达式,匹配所有 HTML 注释(
<!-- 注释 -->
)。- 答案:
/<!--[\s\S]*?-->/
。
- 答案:
四、综合题
- 如何用正则表达式实现一个简单的模板引擎(如替换
{{name}}
为实际值)?- 提示:使用
replace
和分组捕获。
- 提示:使用
- 如何用正则表达式验证一个字符串是否为合法的 JSON 格式?
- 提示:JSON 格式复杂,正则表达式只能做简单验证。
- 如何用正则表达式提取字符串中的所有 URL?
- 提示:结合
match
和 URL 正则表达式。
- 提示:结合
- 如何用正则表达式实现一个简单的词法分析器?
- 提示:结合分组和量词,匹配不同 token。
1. 如何用正则表达式实现一个简单的模板引擎(如替换 {{name}}
为实际值)?
思路:
使用 String.prototype.replace
方法结合正则表达式的分组捕获功能来实现模板字符串的替换。
示例代码:
function renderTemplate(template, data) {
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
return data[key] !== undefined ? data[key] : match;
});
}
const template = "Hello, {{name}}! Welcome to {{place}}.";
const data = { name: "Alice", place: "Wonderland" };
console.log(renderTemplate(template, data)); // 输出: Hello, Alice! Welcome to Wonderland.
2. 如何用正则表达式验证一个字符串是否为合法的 JSON 格式?
注意:
JSON 格式非常复杂,使用正则表达式进行完整的 JSON 验证是不现实的。正则表达式更适合用于简单的模式匹配,而不是复杂的结构化数据验证。建议使用 JSON.parse
方法来验证 JSON 字符串。
示例代码:
function isValidJSON(str) {
try {
JSON.parse(str);
return true;
} catch (e) {
return false;
}
}
console.log(isValidJSON('{"name":"Alice","age":30}')); // 输出: true
console.log(isValidJSON('{"name":"Alice","age":30')); // 输出: false
3. 如何用正则表达式提取字符串中的所有 URL?
思路:
使用 String.prototype.match
方法结合一个简单的 URL 正则表达式来提取字符串中的所有 URL。
示例代码:
function extractURLs(text) {
const urlPattern = /(https?:\/\/[^\s]+)/g;
return text.match(urlPattern) || [];
}
const text = "Check out these links: https://www.example.com and http://www.test.com.";
console.log(extractURLs(text)); // 输出: ["https://www.example.com", "http://www.test.com"]
4. 如何用正则表达式实现一个简单的词法分析器?
思路:
使用正则表达式的分组和量词来匹配不同的 token。这里以一个简单的算术表达式为例,提取数字、运算符和括号。
示例代码:
function tokenize(expression) {
const tokenPattern = /(\d+|[+\-*/()])/g;
return expression.match(tokenPattern) || [];
}
const expression = "3 + 5 * (2 - 8)";
console.log(tokenize(expression)); // 输出: ["3", "+", "5", "*", "(", "2", "-", "8", ")"]
五、面试
腾讯校招笔试
题目
var s = 'abc345efgabcab'
写出三条JS 语句实现一下三个功能(使用正则)
1)去掉字符串中的a、b、c 字符,形成结果:'345efg'
2)将字符串中的数字用中括号括起来,形成结果:'abc[345]efgabcab'
3)将字符串中的每个数字的值分别乘以 2,形成结果:'abc6810efgabcab'
解题
这道题目 ,理解上面基础知识 , 即可写出
var s = 'abc345efgabcab'
// 1)
var reg = /[abc]/g
var res = s.replace(reg,'')
console.log(res)
// 2)
var reg = /\d+/g
var res = s.replace(reg,function(item){
return '[' + item + ']'
})
console.log(res)
// 3)
var reg = /\d+/g
var res = s.replace(reg,function(item){
return item * 2
})
console.log(res)
百度面试
题目
面试官问:下面这段代码怎么实现页面渲染?
let str = '我是{{name}},年龄{{age}},性别{{sex}}'
let person = {
name: '张三',
age: 18,
sex: '男'
}
请手写一个函数compile , 实现这个效果
模板编译原理
模板编译的核心流程(重点!!!)
- 模板字符串转 AST:将模板字符串解析为抽象语法树(AST),AST 是一个树形结构,包含模板的语法结构(标签、属性、文本节点等)。
- 优化 AST:通过静态分析,识别静态节点,后续会跳过这些节点的重新渲染。
- 生成渲染函数:将 AST 转换为渲染函数,渲染函数会生成虚拟 DOM(VNode)。
- 更新视图:将虚拟 DOM 渲染到页面,实现数据驱动视图更新。
我来用最通俗易懂的方式解释模板编译的流程,就像搭积木一样简单:
🏗️ 第1步:把模板变成结构图(AST)
- 想象你要组装乐高,首先要看懂说明书。这里我们把HTML模板(比如
<div id="app">{{message}}</div>
)拆解成一个树形结构图(AST) - 就像用不同颜色的积木区分零件:标签是蓝色积木,属性是红色积木,文本是黄色积木
- 正则表达式就像分类工具(比如用筛子把不同形状的积木分开),帮我们快速识别标签名、属性、文本内容
🌲 举个AST例子:
{
tag: 'div',
attrs: [{ id: 'app' }],
children: [{
type: 'text',
content: '{{message}}'
}]
}
🎯 第2步:给积木做标记(优化AST)
- 找到永远不会变动的积木(比如纯文字的
<div>我是固定标题</div>
) - 给这些"静态积木"贴上荧光贴纸标记
- 之后更新时就可以跳过这些标记过的积木,提升效率
🛠️ 第3步:生成组装说明书(渲染函数)
- 把结构图翻译成JS代码,生成类似这样的函数:
function render() {
return _c('div', { id: 'app' }, _v(message))
}
_c
是创建元素的方法,_v
是创建文本的方法- 这个函数执行后会生成虚拟DOM(就像乐高的3D设计图)
🔄 第4步:按图纸更新(视图更新)
- 当数据变化时(比如message改变),重新生成虚拟DOM
- 对比新旧设计图,找出需要修改的积木块
- 只更新变化的部分到真实DOM,就像只替换掉发黄的积木块
🔑 关键记忆点:
- 模板 → AST(拆解结构)
- 优化AST(找固定零件)
- AST → 渲染函数(写说明书)
- 虚拟DOM → 真实DOM(按图组装)
整个过程就像:
- 把乐高图纸分类整理 📑 →
- 标出固定部分 🏷️ →
- 写成组装步骤 📝 →
- 按步骤拼装/更新积木 🧩
正则表达式在这里就像各种形状的筛子,帮我们快速分离出标签名(圆形筛)、属性(方形筛)、文本(三角形筛),是处理字符串的利器!
模板编译手写
在上面综合题中 , 我们实现了一个
核心代码如下
function renderTemplate(template, data) {
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
return data[key] !== undefined ? data[key] : match;
});
}
发现主要是写正则表达式 reg = /{{(\w+)}}/g , 关于这个正则 ,经上面学习 , 不难 , 涉及到转移字符和全局匹配
ok ! 直接开搓 !!!
法一
let str = '我是{{name}},年龄{{age}},性别{{sex}}'
let person = {
name: '张三',
age: 18,
sex: '男'
}
const reg = /\{\{(\w+)\}\}/g
function complice(template,data){
return template.replace(reg,(match,key)=>{
console.log(match,key)
return data[key] !==undefined ? data[key] : match
})
}
console.log(complice(str,person))
法二
function compile(template, data) {
let reg = /{{(\w+)}}/;
if (reg.test(template)) {
let key = reg.exec(template)[1];
let value = data[key] || '';
template = template.replace(reg, value);
return compile(template, data); // 递归调用
} else {
return template;
}
}
console.log(compile(str, person)); // 输出:我是张三,年龄18,性别男