JavaScript 中的 正则表达式 和 匹配字符串

Posted by cl9000 on August 10, 2021

创造性就是发明、实验、成长、冒险、犯规、犯错和享受乐趣。 ——<玛丽·卢·库克>

介绍

匹配字符串或字符串模式,在最常见的情况下,您需要这些来验证电子邮件、用户输入、文件名或大多数类型的输入字符串。虽然有许多模式匹配库和方法 - 一种久经考验的方法是使用正则表达式来定义一组规则,某个字符串必须遵循以匹配该模式。

JavaScript 中,RegExp类用于表示正则表达式,并且可以与一些使匹配模式更容易的方法结合使用。
显然,使用这些的先决条件是正则表达式的知识。如果您不习惯编写它们,您可以随时使用 RegEx 测试网站,
例如 https://regex101.com/
https://regexr.com/ - 它们直观地显示您的表达式对给定字符串的影响。

本文中,将研究 JavaScript 中的正则表达式RegExp()类的用法以及exec()test()方法。

先来看一些与实现的方法 String 的对象- match()search() 并且 replace() ,正则表达式 RegEx类 可作为一个较短的替代使用。

什么是正则表达式?

在我们深入研究用于使用 RegExJavaScript API 之前,让我们先来看看正则表达式本身。

正则表达式(缩写正则表达式)是用来匹配字符串或字符的不同组合的字符的图案。您需要遵循某些规则才能形成正确的正则表达式。示例:

  • [abc] - 匹配单个字符:a、b 或 c
  • [^abc] - 匹配除a、b 或 c之外的所有字符
  • [a-z] - 匹配范围 az中的任何字符
  • \s - 匹配任何空白字符
  • \w - 匹配任何单词字符

这些是一些基本的,但它们更常用。正则表达式也支持运算符:

  • a? - 运算符 ? 匹配零个或一个字符 a
  • a* - 运算符 * 匹配零个或多个字符 a
  • a+ - 运算符 + 匹配一个或多个字符 a
  • a{n} - 运算符 {n} 精确匹配 n 个字符 a,例如,'o{2}' 不能匹配 "Bob"中的 'o',但是能匹配 "food" 中的两个 o
  • a{n, m} - 运算符 {n, m} 匹配字符 a, 最少匹配 n 次且最多匹配 m 次,例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o
  • \. - 操作符 \ 对字符 . 进行转义,这意味着字符 . 将没有其通常的含义 - 匹配任何字符串 - 但将作为字符匹配.

编写一个正则表达式来检查字符串是否包含 @gmail.com 在字符串的末尾并 a@ 符号之前包含三个字符:

1
2
3
4
5
6
7
8
9
10
11
12
"\w+a{3}@gmail\.com"
// \w - 匹配任何字符
// a{3}-连续匹配三个字符a
// @gmail\.com- 匹配文字字符串"@gmail.com",同时.使用\运算符转义

// 可以匹配字符串,例如:
// otherEmailaaa@gmail.com
// caaa@gmail.com
// 而非
// aaaSomeEmail@gmail.com
// aaa@gmail.com
// aaa@yahoo.com

RegExp 类

JavaScript 中,有两种创建正则表达式的方法:

  1. 使用 RegEx 字面量,这是一种放置在 / 字符之间的模式:
1
2
let regex = "/[abc]+/";
// 如果 `RegEx` 在整个脚本中保持不变,应该使用这种方法,因为 `RegEx` 在脚本自动加载时被编译。
  1. 使用 RegExp() 构造函数:
1
2
let regex = new RegExp("[abc]+");
// 当 `RegEx` 是动态的并且可以在脚本的整个生命周期中更改时,这种方法是首选。它是在运行时编译的,而不是加载时

注意:从 ES6 开始,您还可以将 RegEx 作为构造函数的参数传递

1
let regex = new RegExp(/[abc]+/);

使用 RegExp 时,还可以传递标志 - 具有含义的字符 - 改变模式匹配的方式。其中一些标志是:

  • i - 表示不区分大小写,所以 Aa 匹配时相同
1
2
// Matches both ABC and abc one or more times
let regex = new RegExp("[abc]+", "i");
  • g - 表示将匹配所有可能的情况,而不仅仅是遇到的第一个

  • m - 表示多行模式,允许模式与多行写入的字符串匹配

1
2
3
4
let string = `
This string can also be matched with
Even though it's written in multiple lines
`

RegExp()构造仅用于生成图案进行测试。但是,它包含两种方法可以测试模式并在适合时进行匹配:exec()test()

exec() 函数

exec() 函数在字符串中执行搜索。如果有匹配项,则返回一个包含匹配项信息的数组,否则返回 null

例如检查电子邮件是否以域名结尾 @gmail.com 并包含三个连续的 a 字符 @gmail

1
2
3
4
5
6
7
8
9
10
11
12
// 不区分大小写
let regex = new RegExp(/\w+a{3}@gmail\.com/, "i");
let result1 = regex.exec("someEmailaaa@gmail.com");
let result2 = regex.exec("sOmEEmAiLaAa@gmail.com");

console.log(result1);
console.log(result2);

// 或
let regex = new RegExp(/\w+a{3}@gmail\.com/, "i");
let result1 = regex.exec("someEmailaaa@gmail.com") ?? 'No matched results';
let result2 = regex.exec("sOmEEmAiLaAa@gmail.com") ?? 'No matched results';

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[ 'someEmailaaa@gmail.com',
index: 0,
input: 'someEmailaaa@gmail.com',
groups: undefined ]

[ 'sOmEEmAiLaAa@gmail.com',
index: 0,
input: 'sOmEEmAiLaAa@gmail.com',
groups: undefined ]
// 匹配的字符串
// 匹配字符串开始的索引值
// 输入字符串
// 包含所有命名捕获组的对象的组属性- 在大多数情况下,这将是undefined

// 如果只想隔离匹配的字符串而不需要额外的信息,您可以打印出
console.log(results[0])

exec()方法的一个有趣特性是它会记住它停止执行的字符的索引,所以基本上,你可以一次又一次地调用这个方法,直到你得到一个 null

我们传递一个包含三个字符串的数组;其中两个会匹配,一个不会。为了得到多个结果,我们可以遍历数组并调用,exec()直到得到一个null. 另外,让我们创建一个空数组 matchedStrings 并将匹配的字符串推送给它。

注意:您必须将 g标志传递给RegExp()构造函数才能获得所有结果,而不仅仅是第一个。这样,您将避免进入无限循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let regex = new RegExp(/\w+a{3}@gmail\.com/, "g");

let strings = ["someEmailaaa@gmail.com", "baaa@gmail.com", "baaa@yahoo.com"];
let matchedStrings = [];

let result = regex.exec(strings);
if(result != null) {
matchedStrings.push(result[0]);
}

while(result != null) {
result = regex.exec(strings);
if(result != null) {
matchedStrings.push(result[0]);
}
}

console.log(matchedStrings);
// ["someEmailaaa@gmail.com", "baaa@gmail.com"]
// 可以看到我们从来没有跟踪数组中最后执行的字符串的索引,但exec()知道在哪里继续搜索

test() 函数

test()方法类似于 exec() 除了它不返回包含信息的数组,而是一个简单的 truefalse. 它执行相同的搜索 exec(),如果模式与字符串匹配,则返回 true。否则,返回 false

1
2
3
4
5
6
7
let regex = new RegExp(/\w+a{3}@gmail\.com/, "i");

let results = regex.test("someEmailaaa@gmail.com");
console.log(results); // Output: true

results = regex.test("someEmailaaa@yahoo.com");
console.log(results); // Output: false

对同一个字符串进行两次测试,将得到不同的结果:

1
2
3
4
5
6
7
let regex = new RegExp(/\w+a{3}@gmail\.com/, "g"); // Remember the 'g' flag when working with multiple results

let results = regex.test("someEmailaaa@gmail.com");
console.log(results); // Output: true

results = regex.test("someEmailaaa@gmail.com");
console.log(results); // Output: false

test()字符串数组的用法与 相同 exec(),不同之处在于您将打印出 true / false。实际上,这并不常用,除非您要跟踪匹配字符串的数量。

match()方法

match() 方法是 String 我们将要研究的第一个方法 - 它适用于正则表达式。
它接受一个正则表达式作为参数并返回一个匹配数组,或者 null,如果没有,那么本质上 - 与实例的exec()方法大致相同的 API RegEx

1
2
3
4
5
6
let regex = new RegExp(/\w+a{3}@gmail\.com/, "g"); // Note the 'g' flag

let string = "someEmailaaa@gmail.com";
let resultArray = string.match(regex);

console.log(resultArray); // Output: [ 'someEmailaaa@gmail.com' ]

注意:也可以在此处使用 RegEx 来缩短代码,因为 RegEx 无论如何都会编译为实例:

1
2
3
4
let string = "someEmailaaa@gmail.com";
let resultArray = string.match(/\w+a{3}@gmail\.com/);

console.log(resultArray); // Output: [ 'someEmailaaa@gmail.com' ]

我们将 RegEx 更改为 /[a-z]/ - 以仅匹配小写字符:

1
2
3
4
5
6
7
let regex = new RegExp(/[a-z]/, "g"); // Note the 'g' flag

let string = "someEmailaaa@gmail.com";
let resultArray = string.match(regex);

console.log(resultArray);
// ["s","o","m","e","m","a","i","l","a","a","a","g","m","a","i","l","c","o","m"]

search() 方法

search() 方法搜索传递的模式和字符串之间的匹配项。如果找到匹配项,则返回其索引。否则,该方法返回-1:

1
2
3
4
5
6
7
8
9
10
11
let regex = new RegExp(/\w+a{3}@gmail\.com/, "g"); // Note the 'g' flag

let string = "some string that isn't matched someEmailaaa@gmail.com";
let result = string.search(regex);

console.log(result); // Output: 31

string = "It should return -1 with this string";
result = string.search(regex);

console.log(result); // Output: -1

replace() 方法

replace(to_replace, replace_with) 方法返回一个新字符串,其中模式匹配 to_replace 被替换为 replace_with

它不会更改原始字符串,因为字符串是不可变的。
to_replace 参数可以是一个字符串或一个 RegExp 实例。如果是字符串,则只会替换第一个出现的位置,而如果是 RegExp,则将替换每个出现的位置。
替换 gmail.comyahoo.com

1
2
3
4
5
6
7
8
9
10
11
12
13
let regex = new RegExp(/gmail\.com/, "g"); // Note the 'g' flag

let string = "example@gmail.com";
let result = string.replace(regex, "yahoo.com");

console.log(result); // Output: example@yahoo.com

string = "example1@gmail.com example2@example.com"
result = string.replace(regex, "yahoo.com");

console.log(result); // Output: example1@yahoo.com example2@yahoo.com

console.log(string); // Output: example1@gmail.com example2@gmail.com

总结

  • RegExp类 - 一个类,其目的是用来表示一个正则表达式
  • exec()方法 - 其搜索字符串中的正则表达式,并返回匹配的阵列(具有附加信息)。
  • test()方法 - 这只是如果有一个字符串并返回匹配测试true/ false
  • match()方法 - 在所定义的String,则返回匹配的阵列(没有附加信息)。
  • search()方法 - 在已定义String,返回匹配的索引中找到。
  • replace()方法 - 在已定义String,取代了RegExp()用一个字符串。

参考

关注【公众号】,了解更多。



支付宝打赏 微信打赏

赞赏一下 坚持原创技术分享,您的支持将鼓励我继续创作!