什么是正则表达式?
正则表达式(RegEx)是一个特殊的字符序列,用于匹配字符串中的模式。你可以使用正则表达式来描述一个字符串的规则,从而对其进行搜索、验证或替换。
JavaScript 提供了两种方式来创建正则表达式:
- 字面量语法:
/pattern/ - 构造函数语法:
new RegExp("pattern")
在大多数情况下,我们使用字面量语法,它更加简洁。
正则表达式的基本语法
1. 元字符(Metacharacters)
元字符是正则表达式中具有特殊意义的字符。以下是一些常见的元字符:
| 元字符 | 说明 | 示例 |
|---|---|---|
. | 匹配任意字符(除了换行符) | a.c |
^ | 匹配字符串的开始 | ^abc |
$ | 匹配字符串的结束 | abc$ |
[] | 匹配字符集中的任意字符 | [aeiou] |
| ` | ` | 逻辑“或”运算符,匹配左边或右边的模式 |
() | 分组,表示子表达式 | (abc)+ |
| `` | 转义字符,用来匹配特殊字符,如 . 来匹配点号 | . |
2. 字符类(Character Classes)
字符类用于匹配一组字符中的任何一个。例如:
| 字符类 | 说明 | 示例 |
|---|---|---|
\d | 匹配任何数字,等价于 [0-9] | \d{3} |
\D | 匹配任何非数字字符,等价于 [^0-9] | \D+ |
\w | 匹配任何字母、数字或下划线,等价于 [a-zA-Z0-9_] | \w+ |
\W | 匹配任何非字母、数字或下划线的字符 | \W+ |
\s | 匹配任何空白字符(空格、制表符、换行符等) | \s+ |
\S | 匹配任何非空白字符 | \S+ |
3. 量词(Quantifiers)
量词用于指定前一个字符应当匹配的次数。常用的量词如下:
| 量词 | 说明 | 示例 |
|---|---|---|
* | 匹配前一个字符零次或多次 | a* |
+ | 匹配前一个字符一次或多次 | a+ |
? | 匹配前一个字符零次或一次 | a? |
{n} | 匹配前一个字符恰好出现 n 次 | a{3} |
{n,} | 匹配前一个字符至少出现 n 次 | a{2,} |
{n,m} | 匹配前一个字符出现 n 至 m 次之间的次数 | a{2,4} |
4. 边界匹配(Anchors)
边界匹配用于定位字符串的位置,而不是字符本身。
| 边界符号 | 说明 | 示例 |
|---|---|---|
^ | 匹配字符串的开始 | ^abc |
$ | 匹配字符串的结束 | abc$ |
\b | 匹配单词边界(单词与非单词字符之间) | \bword\b |
\B | 匹配非单词边界 | \Bword\B |
常用正则表达式 API
在 JavaScript 中,有几个方法和正则表达式配合使用,可以让我们非常方便地进行字符串匹配和操作。
1. test()
test() 方法用于测试正则表达式是否与给定字符串匹配。如果匹配,返回 true;否则,返回 false。
const regex = /abc/;
console.log(regex.test("abcdef")); // true
console.log(regex.test("xyz")); // false
2. exec()
exec() 方法执行正则表达式匹配,并返回一个包含匹配结果的数组。如果没有匹配项,返回 null。
const regex = /a(b)c/;
const result = regex.exec("abc");
console.log(result); // ["abc", "b"]
3. match()
match() 方法用于获取与正则表达式匹配的子字符串。如果没有匹配项,返回 null。
const str = "Hello, world!";
const regex = /world/;
console.log(str.match(regex)); // ["world"]
4. replace()
replace() 方法用于替换字符串中的匹配项。
const str = "The quick brown fox";
const result = str.replace(/brown/, "black");
console.log(result); // "The quick black fox"
5. split()
split() 方法根据正则表达式分割字符串,返回一个数组。
const str = "apple,orange,banana";
const result = str.split(/,/);
console.log(result); // ["apple", "orange", "banana"]
实际案例
案例 1:邮箱验证
通过正则表达式验证邮箱的有效性。
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/;
function validateEmail(email) {
return emailRegex.test(email);
}
console.log(validateEmail("test@example.com")); // true
console.log(validateEmail("test@com")); // false
console.log(validateEmail("test@.com")); // false
解释:
^[a-zA-Z0-9._%+-]+:匹配邮箱的用户名部分。@[a-zA-Z0-9.-]+:匹配@后的域名。.[a-zA-Z]{2,}$:匹配域名后缀。
案例 2:手机号验证(中国)
检查中国大陆手机号的格式是否符合规则。
const phoneRegex = /^1[3-9]\d{9}$/;
function validatePhoneNumber(phone) {
return phoneRegex.test(phone);
}
console.log(validatePhoneNumber("13812345678")); // true
console.log(validatePhoneNumber("12345678901")); // false
console.log(validatePhoneNumber("1381234567")); // false
解释:
^1[3-9]:手机号以1开头,第二位为 3 至 9 之间的任意数字。\d{9}$:后面跟着 9 个数字。
案例 3:提取日期(YYYY-MM-DD 格式)
从文本中提取符合日期格式的所有日期。
const text = "今天是 2025-07-22,明天是 2025-07-23,昨天是 2025-07-21。";
const dateRegex = /\d{4}-\d{2}-\d{2}/g;
const dates = text.match(dateRegex);
console.log(dates); // ["2025-07-22", "2025-07-23", "2025-07-21"]
解释:
\d{4}-\d{2}-\d{2}:匹配日期格式YYYY-MM-DD。
案例 4:替换文本中的 URL
在文本中查找并替换所有的网址。
const text = "请访问我们的网站:http://example.com 和 https://openai.com 获取更多信息。";
const urlRegex = /https?://[a-zA-Z0-9.-]+/g;
const newText = text.replace(urlRegex, "[URL]");
console.log(newText);
// 输出: 请访问我们的网站:[URL] 和 [URL] 获取更多信息。
解释:
https?:匹配http或https,问号表示可选的字符。://:匹配://,斜杠是转义字符。[a-zA-Z0-9.-]+:匹配域名部分,允许字母、数字、点和连字符。
案例 5:提取 HTML 标签中的属性
我们可以通过正则表达式从 HTML 标签中提取属性。例如,我们提取 <img src="image.jpg" alt="An image"> 标签中的 src 和 alt 属性:
const html = '<img src="image.jpg" alt="An image">';
const regex = /(\w+)="([^"]+)"/g;
let match;
const attributes = {};
while ((match = regex.exec(html)) !== null) {
attributes[match[1]] = match[2]; // match[1] 是属性名,match[2] 是属性值
}
console.log(attributes);
// 输出: { src: "image.jpg", alt: "An image" }
解释:
(\w+):匹配属性名,使用捕获组捕获。="([^"]+)":匹配等号后面的属性值,确保是用双引号括起来的内容。g:全局匹配,表示查找所有匹配项。
案例 6:提取字符串中的数字
从一段文本中提取所有的数字,例如 "我有2个苹果,3个橙子和5个香蕉。"
const str = "我有2个苹果,3个橙子和5个香蕉。";
const numberRegex = /\d+/g;
const numbers = str.match(numberRegex);
console.log(numbers); // ["2", "3", "5"]
解释:
\d+:匹配一个或多个数字,g表示全局匹配所有数字。
案例 7:查找重复的单词
查找文本中是否有重复出现的单词,使用正则表达式来实现:
const text = "这是一个重复重复的文本。";
const duplicateWordRegex = /\b(\w+)\s+\1\b/g;
const result = text.match(duplicateWordRegex);
console.log(result); // ["重复重复"]
解释:
\b(\w+)\b:匹配一个单词,并将其捕获到第一个捕获组。\s+:匹配一个或多个空白字符。\1:引用第一个捕获的单词,表示重复出现的相同单词。
进阶应用:断言与零宽断言
JavaScript 的正则表达式还支持一些进阶应用,如断言(Assertions)和零宽断言(Zero-width Assertions),可以帮助我们在匹配时不消耗字符。
1. 正向先行断言(Positive Lookahead)
正向先行断言用于检查某个模式后面是否跟着另一个模式,但不消耗字符。常用于验证某个字符后面必须跟着特定的字符。
const regex = /\d(?=\D)/;
console.log("abc1".match(regex)); // ["1"]
解释:
\d:匹配一个数字。(?=\D):正向先行断言,确保数字后面跟着一个非数字字符(即非数字字符跟在数字后面)。
2. 负向先行断言(Negative Lookahead)
负向先行断言用于检查某个模式后面是否没有另一个模式,也不消耗字符。
const regex = /\d(?!\d)/;
console.log("abc123".match(regex)); // ["3"]
解释:
\d:匹配一个数字。(?!\d):负向先行断言,确保数字后面不跟着另一个数字。
3. 零宽反向断言(Negative Lookbehind)
零宽反向断言用于确保某个模式前面没有另一个模式,常用于匹配前面的字符,而不包括前面不需要的字符。
const regex = /(?<!\d)\D+/;
console.log("abc123".match(regex)); // ["abc"]
解释:
(?<!\d):负向后顾断言,确保匹配的部分前面没有数字。\D+:匹配一个或多个非数字字符。
总结
JavaScript 正则表达式是处理字符串和文本的强大工具,掌握它可以帮助你高效地进行文本验证、匹配和替换操作。通过掌握基本的正则语法、常用的 API 和一些高级应用,你可以在开发中轻松应对各种文本处理需求。
以下是学习 JavaScript 正则表达式的几个要点:
- 理解基本语法:正则表达式的元字符、字符类、量词和边界匹配符是构建模式的基础。
- 熟悉常用 API:掌握
test()、exec()、match()、replace()和split()等方法,将使你能够高效地应用正则表达式。 - 灵活运用案例:通过实际的案例学习如何在现实项目中应用正则表达式,包括表单验证、提取信息、替换文本等。
- 探索高级特性:学会使用断言、零宽断言等高级特性,提升正则表达式的灵活性和精确度。
通过不断练习和探索,你会发现正则表达式在 JavaScript 开发中的强大潜力。希望本文对你学习和掌握 JavaScript 正则表达式有所帮助,提升你在开发中的能力!