book5 min read
《正则表达式必知必会》
《正则表达式必知必会》
这篇笔记包含 MDX 无法直接解析的旧 Markdown 语法。
原文内容仍然保留在文件中,可以逐步清理为标准 MDX。
# 《正则表达式必知必会》
正则的知识点其实是很多的,本书言简意赅,总结了正则表达式的常见用法,无论是想快速学习实战,还是日常复习巩固都是非常值得一读的小册子。
## 匹配单个字符
直接使用对应文本就可以匹配单个字符。
```js
/abc/.test('abc'); // true
```
匹配特殊字符,需要加`\`进行转义。
```js
// 匹配.字符
/abc\.com/.test('abc.com'); // true
```
## 匹配一组字符
匹配一组字符中的一个,使用中括号[]。
```js
// 同时能够匹配 x1,y1,z1
/[xyz]1/.test('x1'); // true
/[xyz]1/.test('y1'); // true
/[xyz]1/.test('z1'); // true
```
利用字符集合区间,[a-z]。
```js
// 同时能够匹配a1~z1
/[a-z]1/.test('a1'); // true
/[a-z]1/.test('b1'); // true
/[a-z]1/.test('c1'); // true
/[a-z]1/.test('d1'); // true
// ...
/[a-z]1/.test('z1'); // true
```
## 元字符
元字符是特殊的字符,用来匹配特定含义的文本。
| 元字符 | 含义 |
| ------ | --------------------------------------------------------- |
| . | 匹配任意字符 |
| \n | 匹配换行符 |
| \r | 匹配回车符 |
| \t | 匹配制表符(tab 键) |
| \s | 匹配空白字符,等价于[\f\n\r\t\v] |
| \S | 匹配非空白字符,等价于[^\f\n\r\t\v] |
| \d | 匹配任何一个数字字符等价于[0-9] |
| \D | 匹配任何一个非数字字符,等价于[^0-9] |
| \w | 匹配任何一个字母、数字、下划线字符,等价于[a-zA-Z0-9_] |
| \W | 匹配任何一个非字母、数字、下划线字符,等价于[^a-za-z0-9_] |
## 重复匹配
- ? 匹配 1 次或 0 次。
- \+ 匹配 1 次或多次。
- \* 匹配 0 次或多次。
- {3,} 匹配 3 次或多次。
- {0,3} 至少匹配 0 次,至多匹配 3 次。
```js
// 贪婪型匹配,google匹配到的是最后一个google。
/.*google/.exec('Hello my name is google and I work on google.');
// 匹配结果:Hello my name is google and I work on google
```
因为 \+ 和 \* 都是`贪婪型`元字符,他们在匹配时会尽可能地从一段文本的开头一直匹配到这段文本的末尾。而不是从这段文本的开头匹配到碰到第一个匹配时为止。在不需要这种贪婪行为时,可以使用`懒惰型`匹配。
- \*? 匹配 0 次或多次(懒惰型)
- +? 匹配 1 次或多次(懒惰型)
- {n,} 匹配 n 次或多次(懒惰型)
```js
// 懒惰型匹配,google匹配到的是第一个google。
/.*?google/.exec('Hello my name is google and I work on google.');
// 匹配结果:Hello my name is google
```
## 位置匹配
- \b 匹配一个单词的开始或结尾
- \B 匹配非一个单词的开始或结尾
- ^ 匹配字符串的开头
- \$ 匹配字符串的结尾
```js
// 两段字符串中都包含cat,但只会匹配cat作为单词开头并作为单词结束的cat。
/\bcat\b/.test('This is a cat.'); // true
/\bcat\b/.test('This is a cattle.'); // false
```
启动分行匹配模式,(?m)
例如:(?m)^sss 匹配每一行开头都是 sss 的字符串。
::: warning
经测试 js 并不支持分行匹配。
:::
## 使用子表达式
子表达式,使用括号表示(),作用是把同一个表达式的各个相关部分组合起来。
1、子表达式做或运算:(a|b) 编写 or 条件。
```js
/(a|b)1/.test('a1'); // true
/(a|b)1/.test('b1'); // true
```
2、子表达式处理回溯引用:
```js
/h(2).+h\1/.test('h2zzzh2'); // true
```
3、在替换模式下:$1,$2 代表匹配到的第几个子表达式。
```js
var str = 'Hello Lucy.';
str.replace(/(Lucy)/, 'doctor $1 ');
// Hello doctor Lucy.
```
## 前后查找
?= 向前查找,匹配冒号前面的内容。
```js
/.+(?=:)/.exec('https://'); //匹配到的是 https 不会匹配到:
```
?! 负向前查找,匹配非冒号,之前的内容。
```js
/https(?!\:)/.exec('https://'); //匹配后面不是:的https,这里匹配不到任何结果。
```
?<= 向后查找,匹配\$,之后的内容。
```js
/(?<=\$).+/.exec('$2.5'); // 匹配到的是 2.5 不会匹配到$
```
?<! 负向后查找,匹配非\$,之后的内容
```js
/(?<!\$)2.5/.exec('$2.5'); // 匹配前面没有带$的2.5,这里匹配不到任何结果。
```
## 嵌入条件
如下代码所示:?(1) 的意思是,只有第一个子表达式匹配成功了,才匹配 456 <\/a>。
```js
/(<a>)?123(?(1)456<\/a>)/.exec('<a>123456</a>');
```
::: warning
经测试 js 并不支持。
:::[next-mdx-remote] error compiling MDX: Could not parse expression with acorn More information: https://mdxjs.com/docs/troubleshooting-mdx