正则表达式
正则表达式的概念
正则表达式(Regular Expression,简称 regex 或 regexp)是一种用于匹配字符串中字符组合的模式。在 JavaScript 中,正则表达式也是对象。
正则表达式的创建
1. 使用正则表达式字面量
javascript
const regex = /pattern/flags;
// 示例
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const phoneRegex = /^1[3-9]\d{9}$/;2. 使用 RegExp 构造函数
javascript
const regex = new RegExp('pattern', 'flags');
// 示例
const emailRegex = new RegExp('^[^\s@]+@[^\s@]+\.[^\s@]+$');
const phoneRegex = new RegExp('^1[3-9]\\d{9}$');正则表达式的标志(Flags)
| 标志 | 描述 |
|---|---|
g | 全局搜索,找到所有匹配项 |
i | 忽略大小写 |
m | 多行模式,^ 和 $ 匹配每一行的开始和结束 |
s | 允许 . 匹配换行符 |
u | Unicode 模式,正确处理 Unicode 字符 |
y | 粘性匹配,从目标字符串的当前位置开始匹配 |
正则表达式的元字符
字符类
| 元字符 | 描述 |
|---|---|
. | 匹配除换行符以外的任意字符 |
\d | 匹配数字,等价于 [0-9] |
\D | 匹配非数字,等价于 [^0-9] |
\w | 匹配字母、数字、下划线,等价于 [a-zA-Z0-9_] |
\W | 匹配非字母、数字、下划线,等价于 [^a-zA-Z0-9_] |
\s | 匹配空白字符(空格、制表符、换行符等) |
\S | 匹配非空白字符 |
边界匹配
| 元字符 | 描述 |
|---|---|
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
\b | 匹配单词边界 |
\B | 匹配非单词边界 |
量词
| 元字符 | 描述 |
|---|---|
* | 匹配前面的表达式 0 次或多次,等价于 |
+ | 匹配前面的表达式 1 次或多次,等价于 |
? | 匹配前面的表达式 0 次或 1 次,等价于 |
{n} | 匹配前面的表达式恰好 n 次 |
{n,} | 匹配前面的表达式至少 n 次 |
{n,m} | 匹配前面的表达式至少 n 次,最多 m 次 |
贪婪与非贪婪
- 贪婪匹配:默认情况下,量词会尽可能多地匹配字符
- 非贪婪匹配:在量词后添加
?可以实现非贪婪匹配
javascript
const str = 'aaaa';
// 贪婪匹配
console.log(str.match(/a+/)); // 输出: ['aaaa']
// 非贪婪匹配
console.log(str.match(/a+?/)); // 输出: ['a']分组与捕获
| 元字符 | 描述 |
|---|---|
(x) | 捕获组,匹配 x 并记住匹配项 |
(?:x) | 非捕获组,匹配 x 但不记住匹配项 |
\n | 反向引用,引用第 n 个捕获组 |
javascript
const str = '123-456-7890';
// 捕获组
const regex = /(\d{3})-(\d{3})-(\d{4})/;
const match = str.match(regex);
console.log(match[0]); // 输出: '123-456-7890'
console.log(match[1]); // 输出: '123'
console.log(match[2]); // 输出: '456'
console.log(match[3]); // 输出: '7890'
// 反向引用
const regex2 = /(\d{3})-\1/;
console.log(regex2.test('123-123')); // 输出: true
console.log(regex2.test('123-456')); // 输出: false选择
| 元字符 | 描述 |
|---|---|
x|y | 匹配 x 或 y |
javascript
const regex = /apple|banana|orange/;
console.log(regex.test('apple')); // 输出: true
console.log(regex.test('banana')); // 输出: true
console.log(regex.test('orange')); // 输出: true
console.log(regex.test('grape')); // 输出: false转义字符
| 元字符 | 描述 |
|---|---|
\ | 转义字符,用于匹配特殊字符本身 |
javascript
const regex = /\.\*\+/; // 匹配 .*+
console.log(regex.test('.*+')); // 输出: true正则表达式的方法
RegExp 对象的方法
1. test()
检查字符串是否匹配正则表达式,返回布尔值。
javascript
const regex = /^\d+$/;
console.log(regex.test('123')); // 输出: true
console.log(regex.test('abc')); // 输出: false2. exec()
在字符串中执行正则表达式匹配,返回匹配结果数组或 null。
javascript
const regex = /(\d{3})-(\d{4})/g;
const str = '123-4567, 890-1234';
let match;
while ((match = regex.exec(str)) !== null) {
console.log(`匹配: ${match[0]}, 区号: ${match[1]}, 号码: ${match[2]}`);
console.log(`下一次匹配从索引 ${regex.lastIndex} 开始`);
}字符串的方法
1. match()
在字符串中搜索匹配正则表达式的部分,返回匹配结果数组或 null。
javascript
const str = 'Hello 123 World 456';
const regex = /\d+/g;
console.log(str.match(regex)); // 输出: ['123', '456']2. replace()
替换字符串中匹配正则表达式的部分,返回替换后的字符串。
javascript
const str = 'Hello World';
const regex = /World/;
console.log(str.replace(regex, 'JavaScript')); // 输出: 'Hello JavaScript'
// 使用捕获组
const str2 = '123-456-7890';
const regex2 = /(\d{3})-(\d{3})-(\d{4})/;
console.log(str2.replace(regex2, '$1$2$3')); // 输出: '1234567890'
// 使用函数
const str3 = 'Hello 123 World 456';
const regex3 = /\d+/g;
console.log(str3.replace(regex3, match => parseInt(match) * 2)); // 输出: 'Hello 246 World 912'3. search()
在字符串中搜索匹配正则表达式的部分,返回第一个匹配的索引,没有匹配则返回 -1。
javascript
const str = 'Hello World';
const regex = /World/;
console.log(str.search(regex)); // 输出: 64. split()
根据正则表达式分割字符串,返回分割后的数组。
javascript
const str = 'Hello, World! How are you?';
const regex = /\s*[,!?.]\s*/;
console.log(str.split(regex)); // 输出: ['Hello', 'World', 'How are you', '']常见正则表达式模式
1. 邮箱地址
javascript
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;2. 手机号码(中国大陆)
javascript
const phoneRegex = /^1[3-9]\d{9}$/;3. 身份证号码(中国大陆)
javascript
const idCardRegex = /^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/;4. URL
javascript
const urlRegex = /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/;5. 密码强度
要求:至少8位,包含大小写字母、数字和特殊字符
javascript
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;6. IPv4 地址
javascript
const ipv4Regex = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;7. 日期格式(YYYY-MM-DD)
javascript
const dateRegex = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/;正则表达式的性能优化
- 避免过度使用正则表达式:对于简单的字符串操作,使用字符串方法可能更高效
- 使用具体的模式:避免使用过于宽泛的模式,如
.* - 使用非捕获组:对于不需要捕获的分组,使用
(?:x)而不是(x) - 使用粘性匹配:对于多次匹配同一字符串,使用
y标志可以提高性能 - 避免回溯:设计正则表达式时,尽量避免导致大量回溯的模式
正则表达式的实际应用
1. 表单验证
javascript
function validateForm() {
const email = document.getElementById('email').value;
const phone = document.getElementById('phone').value;
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const phoneRegex = /^1[3-9]\d{9}$/;
if (!emailRegex.test(email)) {
alert('请输入有效的邮箱地址');
return false;
}
if (!phoneRegex.test(phone)) {
alert('请输入有效的手机号码');
return false;
}
return true;
}2. 文本处理
javascript
// 提取文本中的所有数字
function extractNumbers(text) {
const regex = /\d+/g;
return text.match(regex) || [];
}
// 替换文本中的敏感词
function censorText(text, sensitiveWords) {
const regex = new RegExp(sensitiveWords.join('|'), 'gi');
return text.replace(regex, '*'.repeat(5));
}3. 数据提取
javascript
// 从 URL 中提取查询参数
function getQueryParams(url) {
const params = {};
const regex = /[?&]([^=&]+)=([^&]*)/g;
let match;
while ((match = regex.exec(url)) !== null) {
params[decodeURIComponent(match[1])] = decodeURIComponent(match[2]);
}
return params;
}正则表达式的局限性
- 性能问题:复杂的正则表达式可能导致性能下降
- 可读性:复杂的正则表达式难以理解和维护
- 功能限制:某些复杂的模式可能无法用正则表达式完全表达
- 跨语言差异:不同编程语言的正则表达式语法可能有差异
总结
正则表达式是一种强大的工具,用于匹配、搜索、替换和提取字符串中的模式。在 JavaScript 中,正则表达式可以通过字面量或 RegExp 构造函数创建,并使用各种元字符和标志来定义匹配模式。
掌握正则表达式对于前端开发非常重要,它可以帮助我们:
- 验证用户输入
- 处理和转换文本
- 提取数据
- 进行复杂的字符串操作
虽然正则表达式有时看起来复杂,但通过理解其基本原理和常见模式,我们可以有效地使用它来解决各种字符串处理问题。