资源
前言
正则表达式是 描述字符串匹配的模式(模式在这里可以理解为序列或者特征)
描述一组序列特征
- 序列包含了哪些字符,以及他们的顺序, 比如说: abc, cba
- 序列左右边界, a 开头 d 结尾, 可以匹配 acccd a111d
偏实战
可以在IDE中使用正则表达式查找和替换
开发中可以使用正则表达式解决字符串校验与数据处理问题
使用场景
正则表达式 的用途
- 对字符串进行子串校验
- 对字符串做子串替换操作
- 对字符串做子串提取
编辑器查找与替换
vscode
type-challenges 中查找所有类型定义, 查找所有的 a 标签
vim
批量替换, 替换 host ip,
:%s/foo/bar/g
代码开发
开发参数校验
手机号, 网址, ip地址, 金额, 身份证, 日期
开发数据处理
解析 html 文件, 文件匹配, 子串提取, 子串替换
提取 链接, 提取某个标签的内容, 内容查找
基础
包含普通字符, 元字符
元字符让正则表达式拥有了处理能力, 是专用字符, 可以使用简短的语法 表达复杂序列或者规则
元字符又可分为 字符集合, 量词, 转义字符, 位置匹配
普通字符
单个字符或者一组字符序列
// 校验 google
'<a href="https://www.baidu.com"></a>'.test(/google/) // false
// 校验 百度
'<a href="https://www.baidu.com"></a>'.test(/baidu/) // true
字符集合
表达一组字符的匹配, 某个字符位置上存在匹配多种字符, 也可以称为纵向匹配
// 字符集合
'bat nat cat'
/[bcn]at/
// 字符范围
'Today is Thursday,v me $50'
/[0-9]/
/[a-d]/
// 匹配英文字符
/[a-zA-Z]/
// 匹配数字
/[0-9]/
// 取非
'crazy thursday, v me $50.0'
/[^a-z .]/
字符集合里面都是普通字符
特殊字符
与正则表达式引擎的约定
.:匹配除了换行符之外的任何单个字符
'<a href="https://www.baidu.com"></a>
<a href="http://www.baidu.com"></a>'
/./
: 转义字符: 将下一个字符标记为特殊字符或原义字符
'3.14 3214'
/3\.14/
'/** regex **/ const a = 1'
/\/\*\*.+\*\*\//
'21f;';[]22_aa'
/\w+/ -> [A-Za-z0-9_]
/\W+/
/\d+/ -> [0-9]
/\n/
/\s/ -> 空格
|: 逻辑或运算符
// example
'this is https://baidu.com.'
'this is ftp://127.0.0.1'
// 正则
/(https|ftp):\/\//
量词
横向匹配
{}: 括号量词匹配
// example
'15115438096'
// 固定数量
/\d{11}/
// example
'2574073960'
'973017473'
'100000'
'1000'
'32131231232312323'
// 固定左右边界
/\d{6,12}/
// 固定左边界
/\d{6,}/
+: 匹配前面一个表达式一次或者多次 (贪婪匹配)
// example
'qq: 2574073960'
'973017473'
'100000'
'1000'
'32131231232312323'
// 正则
/qq: \d+/
*: 匹配前面一个表达式 0 次或者多次
// example
'<a href="https://www.baidu.com"></a>'
'<a href="https://www.baidu.com"></a>'
'<a href="https://"></a>'
// 正则
/https:\/\/.*/
?: 匹配前面字符 0 次或者 1次, 如果是接在量词后面, 表示非贪婪模式, 尽可能少匹配字符
// 匹配链接
'<a href="https://www.baidu.com"></a>'
'<a href="http://www.baidu.com"></a>'
'<a href="https://"></a>'
'https://'
// 正则
/https?:\/\/[^"]+/
// 非贪婪模式匹配所有链接
/href=".*?"/
位置匹配
位置: 字符间的空档即为位置, 正则要么匹配字符, 要么匹配位置
1.单词边界
// example
'Regular expressions are extremely useful in extracting information from text such as code, log files, spreadsheets, or even documents.'
// 正则
/\b/
/\B/
2.开头结尾
// example
'1511543809612'
'151154380962'
'15115438096'
// 正则
/^\d{11}$/
// example
'https://example.com'
'https://juejin.im'
'tthttps://juejin.im'
// 正则
/^https:\/\/.+/
进阶
断言(前后查找)
对当前匹配序列做进一步条件判断
1.向前肯定断言, (?=)
以什么结尾的条件
// example
'README.md'
'README.zh-CN.md'
'README.ko.md'
'a.txt'
// 正则
/.+(?=\.md)/
2.向前否定断言
不以什么结尾的条件
// example
'windows 2000'
'windows xp'
'windows 11'
'windows 10'
// 正则
/windows\s(?!11|10)/
3.向后肯定断言
以什么开头的条件
// example
'<a href="https://www.baidu.com"></a>'
'https://www.baidu.com'
'<img src="https://www.baidu.com/a.png"/>'
// 正则
/(?<=href=")https:\/\/[^"]+/
4.向后否定断言
不以什么开头的条件
const regex = /(?<!href=")https:\/\/.+(?=")/
回溯
/".*"/
/"[^"]*"/
反向引用
捕获: 记录子表达式
// example
'<a href="https://www.baidu.com">nihao</a>'
// 正则
/(https:\/\/)([^"]+)/
不捕获
// example
'this is https://baidu.com'
'this is ftp://127.0.0.1'
// 正则
/(?:https|ftp):\/\/.+/
引用: 反向引用捕获的子表达式
// example
'<h1>nihao</h1>'
'<h2>wo</h2>'
'<h1>ta</h2>'
// 正则
/(?<=<(h[1-6])>).+?(?=<\/\1>)/
原理剖析
可以参照编译原理分享-词法分析篇
正则表达式引擎
DFA: 确定型有穷自动机 NFA: 非确定型有穷自动机
考试
1. ip 地址
匹配合法 ip 地址
// 只匹配下面这类合法 ip 地址
'192.168.0.1'
'127.0.0.1'
'23.54.23.167'
// test case
'1000.1.1.1'
'192..168.0.1'
'192.168.0.1000'
'192.168.1.a'
'256.22.23.4'
/^((2([0-4]\d|5[0-5])|1?\d{1,2})\.){3}(2([0-4]\d|5[0-5])|1?\d{1,2})$/ // 参考答案
2. 金额
匹配金额数字
// 提取金额 匹配示例
'v me $50' -> '50'
'v me $1.5' -> '1.5'
'v me $-50' -> '-50'
// test case
'v me $1.'
'v me $.5'
'v me $.22'
'v me $22.'
/-?(\d+\.\d+|(?<!\D+\.|\.\d)\d+(?!\.\D+|\d+\.))/ // 参考答案
3. 日期
匹配合法日期
// 匹配这类日期格式
'2023.3.30'
'2023/3/30'
'2023-3-30'
// test case
'2023.3/30'
'2023-3/30'
'2023/13/30'
'2023/12/32'
'2023/1/'
4. 提取注释内容
匹配注释内容
// 提取示例
'/** TODO:此处有bug1 **/' -> 'TODO:此处有bug1'
'// TODO:此处有bug4' -> 'TODO:此处有bug4'
// test case
'/** TODO:此处有bug1 **/'
'// TODO:此处有bug4'
5. 千分位金额格式化
位置匹配应用, 将金额格式化为千分位表示
// 匹配示例
'12345' -> '12,345'
'123456789' -> '123,456,789'
'123456.1234' -> '123,456.1234'
// test case
'12345'
'123456789'
'123456.1234'
/(?<!\.\d*)\B(?=(?:\d{3})+\b)/ // 参考答案