# 正则表达式 **Repository Path**: jsopy/regular-expression ## Basic Information - **Project Name**: 正则表达式 - **Description**: 正则总结 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-01-29 - **Last Updated**: 2024-10-31 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 快速开始 正则表达式是衡量纯许愿水平的一个侧面标准 我们用正则表达式主要就两点 1.查找 2.替换 # 阅读本文档注意 - 正则是匹配模式,要么匹配字符,要么匹配位置 第 1 章和第 2 章从这个角度去讲解正则的基础 - 在正则中可以使用括号来捕获数据,要么在 API 中进行分组引用,要么在正则里进行反向引用 这是第三章的主题,讲解正则中括号的作用 - 学习正则表达式,需要了解匹配原理 第四章讲解了正则表达式的回溯法原理.另外在第六章,也讲解了正则表达式的整体工作原理 - 不仅能看懂别人的正则表达式,还要自己会写正则 第五章从读的角度去拆分一个正则表达式。第 6 章从写的角度,去构建一个正则表达式 - 学习正则,是为了在真实世界里面应用 第 7 章为了讲解正则的用法,和相关 API 需要注意的地方 # 正则表达式不要背 个人建议大家可以利用 [跳转](https://regexper.com/#)来可视化自己写的正则表达式 例如 /\d\w+/ 这个正则表达式生成的状态机图 ![展示](./logo/1.jpg) # 从字符出发 我们学习一个系统化的知识,一定要从基础构成来了解.正则表达式的基本组成元素可以分为:`字符和元字符` 字符很好理解,就是基础的计算机字符编码,通常正则表达式里面就是用数字,英文字母。而元字符,也被称为`特殊字符`,是一些用来表示特殊语义的字符如 ^表示非,|表示或,等等.利用这些元字符才能构造出强大的表达式模式 ## 单个字符 最简单的正则表达式可以由简单的数字和字母组成.没有特殊的语义.纯粹就是--对应的关系.比如想在`apple`这个单词里面找到`a`这个字符就直接用 `/a/` 这个正则就好了 如果想匹配特殊字符的话,就得请出我们第一个元字符了`\`它表示转义符,顾名思义 就是让其后续的字符失去其原本的含义 比如我想匹配`*`这个符号,由于`*`本身就是个特殊字符,所以我们利用转义字符`\`来让其失去本来的含义 ```javascript /\*/; ``` 如果本身这个字符不是特殊字符,那么转义符号就会让它拥有特殊的含义,我们常常需要匹配一些特殊的字符,比如空格,制表符,回车,换行等.而这些就需要我们用转义字符来匹配.为了方便记忆 我用如下表格 | 特殊字符 | 正则表达式 | 记忆方式 | | ---------- | ---------- | --------------------------------- | | 换行符 | \n | new line | | 换页符 | \f | form feed | | 回车符 | \r | return | | 空白符 | \s | space | | 制表符 | \t | tab | | 垂直制表符 | \v | vertical tab | | 回退符 | [\b] | backspace 用[]是为了避免和\b 重复 | ## 多个字符 单个字符的映射关系是一对一的,即正则表达式被用来筛选匹配的字符只有一个,而这显然是不够的,只要引入结合区间和通配符的方式就可以实现一对多的匹配 在正则表达式里,集合的定义方式就是使用中括号`[`和`]`,如`/[123]/`这个正则就能同时匹配 1,2,3 三个字符.那如果我想匹配所有的数字该怎么办?这个时候需要`-`来表示区间范围,利用`/[0-9]/`就能匹配所有的数字. `/[a-z]/`则可以匹配所有小写的英文字母 即使有了集合和区间的定义方式,如果要同时匹配多个字符也还是要一一列举.这是太繁琐了.所以在正则表达式里衍生了一批用来同时匹配多个字符的简便正则表达式 | 匹配区间 | 正则表达式 | 记忆方式 | | ------------------------------------------ | ---------- | ------------------- | | 除了换行符之外的任何字符 | . | 句号,除了句子结束符 | | 单个数字 [0,9] | \d | digit | | 除了[0-9] | \D | nodigit | | 包括下划线在内的单个字符,[A-Za-z0-9_] | \w | word | | 非单字字符 | \W | notword | | 匹配空白字符包括空格,制表符,换页符和换行符 | \s | space | | 匹配非空白字符 | \S | nospace | ## 循环和重复 一对一和一对多都说完了,下面介绍如何同时匹配多个字符,要实现多个字符的匹配,我们只要多次循环,重复使用我们之前的表达式即可.依据循环次数来分,我们可以分为 0 次,1 次,多次,特定次 ### 0 | 1 元字符 `?`代表匹配一个字符或者 0 个字符.如果你要匹配`color`和`colour`这两个单词,就需要同时保证`u`这个字符是否出现都能被匹配到,所以正则表达式应该`/colou?r/` ### >=0 元字符`*`用来匹配 0 个字符或者无数个字符.通常用来过滤某些可有可无的字符串(贪婪模式) ### >=1 元字符`+`适用于匹配同个字符出现 1 次或多次的情况 ### 特定次数 在某些情况下 我们需要匹配特定的重复次数 元字符 `{`和`}`用来给重复匹配设置精确的区间范围.如`a`我想匹配 3 次,那我可以使用 `/a{3}/`这个正则,如果说我想匹配至少两次就是用`/a{2,}/`这个正则 ```bash - {x}: x次 - {min,max} 介于min次到max次之间 - {min,} 至少min次 - {0,max} 最多max次 ``` 由于元字符比较抽象,方便记忆 如下 | 匹配原则 | 元字符 | 联想方式 | | -------------- | ------------- | ---------------------- | | 0 次或 1 次 | ? | 懒人爱提问(懒惰模式) | | 0 次或者无数次 | \* | 贪婪者只能想(懒人模式) | | 1 次或者无数次 | + | 一加,+1 | | 特定次数 | {x},{min,max} | 规定次数 | ### 单词边界 单词边界 比如`cat` cat 是一个单词.两边都是空白,那我们可以用`/\bcat\b/`来匹配 ### 字符串边界 元字符`^`来匹配元字符的开头.而元字符`$`来匹配字符串的末尾. 特别注意要是多行模式,我们需要开启多行模式`m` 比如 ```bash I am scq000. I am scq000. I am scq000. ``` 我们可以使用 `/^I am scq000\.$/m` 来表示,m 就表示 multiple line 的首字母,正则模式里面除了 m 外比较常用的还有`i`和`g` 前者的意思是忽略大小写后者的意思是全局匹配(找到所有符合匹配的) | 边界和标志 | 正则表达式 | 记忆方式 | | ---------- | ---------- | ----------------------------- | | 单词边界 | \b | boundary | | 非单词边界 | \B | notboundary | | 字符串开头 | ^ | 上开头 | | 字符串结尾 | $ | 美金结束 | | 多行模式 | m | multiple of lines | | 忽略大小写 | i | ignore case, case-insensitive | | 全局模式 | g | global | ### 子表达式 字符匹配我们介绍的差不多了,更加高级的用法就得用到子表达式了。通过嵌套递归和自身引用可以让正则发挥更强大的功能。 从简单到复杂的正则表达式演变通常要采用分组、回溯引用和逻辑处理的思想。利用这三种规则,可以推演出无限复杂的正则表达式。 ### 分组 所有`(`和`)`包含的正则表达式被分为一组,每个分组都是一个子表达式.它也是构成高级正则表达式的基础。如果只是使用简单的(regex)匹配语法本质上和不分组是一样的,如果要发挥它强大的作用,往往要结合回溯引用的方式。 ### 回溯引用 所谓回溯引用值得是模式的后面部分引用前面已经匹配到的子字符串.你可以把它想象成是变量,回溯引用的语法想 `\1`,`\2`,...其中`\1`表示引用的第一个子表达式,`\2`表示引用的第二个子表达式,以此类推 而 `\0`表示整个表达式 回溯引用在替换字符串中十分常用.语法上有一些区别,用`$1`,`$2`...来引用要被替换的字符串 ```javascript let str = "abc abc 123"; str.replace(/(ab)c/g, "$1g"); //得到的结果就是'abg abg 123' ``` ### 前向查找 (?=p) 其中 p 是一个子模式,即 p 前面的位置.或者说该位置后面的字符要匹配 p 比如(?=l)表示'l'字符前面的位置 ```javascript var result = "hello".replace(/(?=l)/g, "#"); console.log(result); //结果 'he#l#lo' ``` ### 后向查找 (?<=p) 其中 p 是一个子模式,即 p 后面的位置 ```javascript let result = "hello".replace(/(?<=l)/g, "#"); console.log(result); //结果 "hel#l#o" ``` ### 前向非查找 (?!p) 其中 p 就是一个子模式,找到不满足 p 前面的位置 ```javascript var result = "hello".replace(/(?!l)/g, "#"); console.log(result); //结果 "#h#ell#o#" ``` ### 后向非查找 (?