javascript 中的正则表达式

javascript 中的正则表达式

各语言对正则表达式都有支持,其中支持最好的我觉得应该是 C# 了,shell 的正则最麻烦,大概只有 -P 模式才好点。
javascript 对正则的支持也不错,目前新版的 chrome 跟 node 已经支持了逆向环视。本篇文章主要是对 javascript 中的正则表达式做一个总结。

阅读之前需要对正则有一个基础概念。

## 声明正则表达式

正则表达式的声明方式有两种:

  1. 使用构造函数来 new 一个 RegExp 对象,这种一般是正则需要动态构建的时候使用。
js
var reg = new RegExp('正则表达式主体', '修饰符(可选)');
  1. 使用对象字面量来声明,大部分情况会这么使用。
js
var reg = /正则表达式主体/修符饰(可选);

## 字符串方法

字符串中使用正则表达式作为参数的方法。

使用频率:★☆☆☆☆

用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串,并返回子串的起始位置。
但是这个方法用的是真的少,一般直接用 indexOf 就够了。

js
1var index = `helloworld`.search(/l/);
2console.log(index); // output: 2

### replace

使用频率:★★★★☆

使用正则表达式替换字符串中的内容,返回替换后的字符串。很常用的方法。

js
1语法:
2str.replace(regexp|substr, newSubStr|function)
参数类型描述
regexpRegExp需要被替换的字符串对应的正则表达式
substrstring需要被替换的字符串
newSubStrstring替换的字符串
functionFunction用于返回替换字符串的方法
js
1// 举个function的例子,如果想把字符串中script标签的地址,
2// 如果是相对路径就加一个cdn的prefix:
3
4var content = `
5<script src="1.js"></script>
6<script src="https://xxx/2.js"></script>
7<script src="3.js"></script>
8`;
9
10content.replace(/(script\s*src=")([^"]+)/g, (g0, g1, g2) => {
11    // g0 是整个匹配的字符串
12    // g1 是第一个子串
13    // g2 是第二个子串,如果还有子串,就是 g3,g4...
14
15    // 如果是某个网络地址
16    if (/^http/.test(g2)) {
17        return g0;
18    }
19    // 如果是相对路径,返回cdn的地址
20    return g1 + 'https://cdn.xxx.com/' + g2;
21});
22
23// output:
24// <script src="https://cdn.xxx.com/1.js"></script>
25// <script src="https://xxx/2.js"></script>
26// <script src="https://cdn.xxx.com/3.js"></script>

### match

使用频率:★★★★☆

方法检索返回一个字符串匹配正则表达式的的结果(RegExpMatchArray)。如果没有匹配到,则返回 null

RegExpMatchArray 是一个伪数组,还包括了一些其他的属性。这一段摘自 MDN

属性描述
groups一个捕获组数组 或 undefined(如果没有定义命名捕获组)。
index匹配的结果的开始位置
input搜索的字符串

#### 全局匹配的情况

在含有 g 参数的时候,会返回所有与正则表达式匹配的结果,忽略子组的匹配。

适用于查找所有匹配项。

js
1const content = `
2<script src="1.js"></script>
3<script src="2.js"></script>
4<script src="3.js"></script>
5`;
6
7const reg = /src="(\S+?)"/g;
8
9console.log(content.match(reg));
10// output:
11// ['src="1.js"', 'src="2.js"', 'src="3.js"']

#### 只获取匹配到的第一项

在无 g 参数的时候,会返回 [整个匹配项子组 1子组 2...]

适用于提取多个特定字符串。

js
1// 如果去掉 g ,会返回子组的匹配情况。提取某个特定字符串会经常这么用。
2
3const content = `
4<script src="1.js"></script>
5<script src="2.js"></script>
6<script src="3.js"></script>
7`;
8
9const reg = /src="(\S+?)"/;
10
11console.log(content.match(reg));
12// output:
13// ['src="1.js"', '1.js']

## 正则表达式方法

RegExp 对象的一些以 string 为参数的方法。

### test

使用频率:★★★★☆

通常用于检测一个字符串是否符合某个正则的规则,返回 true/false

js
1const content = '123456';
2
3console.log(/^\d+$/.test(content));
4// output: true

切记使用 test 的时候不要用全局匹配 g,如果用全局匹配的话,每次匹配都会记录匹配的位置,下次匹配会从上一次匹配到的位置之后进行查找。

### exec

使用频率:★★★★☆

exec 通常用于在全局查找包含了多个子项的情景,功能十分强大。

reg.exec 在每次调用,都会获取一次 string.match 调用的结果,得到 [整个匹配项子组 1子组 2...],然后记录之前匹配的位置,下次调用就从新的位置开始查找。

记住 exec 是跟 g 一起用的,如果不是全局模式,那么每次调用都会从头开始查找,失去了查找所有的能力。

js
1const content = `
2<script data-key="key1" src="1.js"></script>
3<script data-key="key2" src="2.js"></script>
4<script data-key="key3" src="3.js"></script>
5`;
6
7const reg = /data-key="(\S+?)"\s*src="(\S+?)"/g;
8
9let m;
10let matches = [];
11
12while ((m = reg.exec(content))) {
13    matches.push(m);
14}
15
16console.log(matches);
17
18// output:
19// [
20//     ['data-key="key1" src="1.js"', 'key1', '1.js'],
21//     ['data-key="key2" src="2.js"', 'key2', '2.js'],
22//     ['data-key="key3" src="3.js"', 'key3', '3.js']
23// ]

exec 每次获取到到也是一个伪数组,额外还有 indexinput 字段,index表示前一次匹配到的位置,input表示原始的字符串。

之前写过一篇文章 写一个 javascript 模板引擎,其中的匹配使用了 exec 方法,有兴趣可以移步。

## 一些使用情景

这里罗列一些在日常工作或学习中感觉值得记下来的场景。

### 包含了且只包含

判断一个字符串,包含了 abc 3 种字符,且只包含了这 3 种字符。

js
1const reg = /^(?=.*a)(?=.*b)(?=.*c)[abc]+$/;
2
3reg.test('a'); // false
4reg.test('abc'); // true
5reg.test('abcd'); // false

这里用了 正向环视(?=xxx)表示接下来有什么,那么 /^(?=.*a)(?=.*b)(?=.*c)[abc]+$/ 就有了这些约束:

  1. 后面有 a
  2. 后面有 b
  3. 后面有 c
  4. 整个字符串由 a 或 b 或 c 组成

归纳一下,就表示:字符串中包含的有 abc,且只包含了 abc

环视 这个词,相同含义的还有 预查断言等,延伸出来的什么 正向肯定预查,0 宽断言之类,大多是翻译问题。为了避免沟通上的障碍,以《精通正则表达式》这本书中为准,使用环视来称呼这种查找。

## 结语

正则表达式很强大,使用情景也很复杂,本篇文章只是罗列了常用方法的用法,想要去完全掌握和提高还是需要日积月累。

之后会慢慢补充一些使用场景进来。

to-be-continued
avatar

闲暇时候的文章

会写一些 代码、心情、生活、食物、balabala 我也不知道什么类型的东西 >_<#@!

如果碰巧你找到感兴趣的东西,可以来瞅瞅。

Copyright © 2017 - 2023 xieshuang. All Rights Reserved. Power by k8s + nestjs + next + vue + typescript.
鄂ICP备20008501号-1