【正则表达式实战指南:从入门到精通】

本文将系统讲解正则表达式的核心语法和实战技巧,通过大量实例帮助你掌握这一强大的文本处理工具,提升开发效率。

📋 目录


一、正则表达式基础

1.1 创建正则表达式

javascript 复制代码
// 字面量方式(推荐)
const regex1 = /pattern/flags;

// 构造函数方式(动态创建)
const regex2 = new RegExp('pattern', 'flags');

// 示例
const emailRegex = /^\S+@\S+\.\S+$/;
const dynamicRegex = new RegExp(`^${userInput}$`, 'i');

1.2 常用标志(Flags)

标志 说明 示例
g 全局匹配 /a/g 匹配所有a
i 忽略大小写 /a/i 匹配a和A
m 多行模式 ^$匹配每行开头结尾
s dotAll模式 .匹配包括换行符
u Unicode模式 正确处理Unicode
y 粘性匹配 从lastIndex开始匹配
javascript 复制代码
// 标志组合使用
const regex = /hello/gi;  // 全局、忽略大小写

'Hello hello HELLO'.match(/hello/gi);
// ['Hello', 'hello', 'HELLO']

1.3 基本匹配

javascript 复制代码
// 精确匹配
/hello/.test('hello world');  // true

// 字符类
/[abc]/.test('apple');        // true,匹配a、b或c中任一个
/[a-z]/.test('hello');        // true,匹配小写字母
/[A-Z]/.test('Hello');        // true,匹配大写字母
/[0-9]/.test('123');          // true,匹配数字
/[a-zA-Z0-9]/.test('a1');     // true,匹配字母数字

// 否定字符类
/[^abc]/.test('def');         // true,匹配非a、b、c的字符
/[^0-9]/.test('abc');         // true,匹配非数字

二、元字符与量词

2.1 常用元字符

javascript 复制代码
// 字符类简写
\d  // 数字 [0-9]
\D  // 非数字 [^0-9]
\w  // 单词字符 [a-zA-Z0-9_]
\W  // 非单词字符 [^a-zA-Z0-9_]
\s  // 空白字符 [ \t\n\r\f\v]
\S  // 非空白字符
.   // 任意字符(除换行符)

// 示例
/\d{3}/.test('123');          // true
/\w+/.test('hello_123');      // true
/\s/.test('hello world');     // true

2.2 量词

javascript 复制代码
// 基本量词
*     // 0次或多次
+     // 1次或多次
?     // 0次或1次
{n}   // 恰好n次
{n,}  // 至少n次
{n,m} // n到m次

// 示例
/a*/.test('');           // true,0次
/a+/.test('aaa');        // true,1次或多次
/a?/.test('b');          // true,0次或1次
/a{3}/.test('aaa');      // true,恰好3次
/a{2,4}/.test('aaa');    // true,2到4次

2.3 贪婪与非贪婪

javascript 复制代码
// 贪婪模式(默认)- 尽可能多匹配
const greedy = /<.+>/;
'<div>content</div>'.match(greedy);
// ['<div>content</div>']

// 非贪婪模式 - 尽可能少匹配
const lazy = /<.+?>/;
'<div>content</div>'.match(lazy);
// ['<div>']

// 非贪婪量词
*?    // 0次或多次(非贪婪)
+?    // 1次或多次(非贪婪)
??    // 0次或1次(非贪婪)
{n,m}? // n到m次(非贪婪)

2.4 边界匹配

javascript 复制代码
^     // 字符串开头(多行模式下匹配行开头)
$     // 字符串结尾(多行模式下匹配行结尾)
\b    // 单词边界
\B    // 非单词边界

// 示例
/^hello/.test('hello world');   // true
/world$/.test('hello world');   // true
/\bword\b/.test('a word here'); // true
/\Bword/.test('password');      // true

三、分组与引用

3.1 捕获分组

javascript 复制代码
// 基本分组
const regex = /(\d{4})-(\d{2})-(\d{2})/;
const match = '2024-01-15'.match(regex);
// match[0] = '2024-01-15' (完整匹配)
// match[1] = '2024' (第一个分组)
// match[2] = '01' (第二个分组)
// match[3] = '15' (第三个分组)

// 命名分组
const namedRegex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const namedMatch = '2024-01-15'.match(namedRegex);
// namedMatch.groups.year = '2024'
// namedMatch.groups.month = '01'
// namedMatch.groups.day = '15'

3.2 非捕获分组

javascript 复制代码
// 非捕获分组 (?:...)
const regex = /(?:https?|ftp):\/\/(\S+)/;
const match = 'https://example.com'.match(regex);
// match[1] = 'example.com' (只捕获域名)

// 对比捕获分组
const captureRegex = /(https?|ftp):\/\/(\S+)/;
const captureMatch = 'https://example.com'.match(captureRegex);
// captureMatch[1] = 'https'
// captureMatch[2] = 'example.com'

3.3 反向引用

javascript 复制代码
// 引用前面的捕获分组
const regex = /(['"]).*?\1/;  // \1 引用第一个分组

regex.test('"hello"');   // true
regex.test("'hello'");   // true
regex.test('"hello\'');  // false,引号不匹配

// 命名反向引用
const namedRegex = /(?<quote>['"]).*?\k<quote>/;
namedRegex.test('"hello"');  // true

// 替换中使用引用
'hello world'.replace(/(\w+) (\w+)/, '$2 $1');
// 'world hello'

// 命名引用替换
'2024-01-15'.replace(
  /(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/,
  '$<d>/$<m>/$<y>'
);
// '15/01/2024'

3.4 选择分支

javascript 复制代码
// 或运算 |
const regex = /cat|dog|bird/;
regex.test('I have a cat');  // true
regex.test('I have a dog');  // true

// 分组中的选择
const urlRegex = /https?:\/\/(www\.)?example\.(com|org|net)/;
urlRegex.test('https://example.com');      // true
urlRegex.test('https://www.example.org');  // true

四、断言与边界

4.1 先行断言

javascript 复制代码
// 正向先行断言 (?=...)
// 匹配后面是...的位置
const regex = /\d+(?=元)/;
'100元'.match(regex);  // ['100']
'100$'.match(regex);   // null

// 负向先行断言 (?!...)
// 匹配后面不是...的位置
const regex2 = /\d+(?!元)/;
'100$'.match(regex2);  // ['100']
'100元'.match(regex2); // ['10'] (匹配到10,因为0后面是元)

4.2 后行断言

javascript 复制代码
// 正向后行断言 (?<=...)
// 匹配前面是...的位置
const regex = /(?<=\$)\d+/;
'$100'.match(regex);   // ['100']
'€100'.match(regex);   // null

// 负向后行断言 (?<!...)
// 匹配前面不是...的位置
const regex2 = /(?<!\$)\d+/;
'€100'.match(regex2);  // ['100']
'$100'.match(regex2);  // ['00']

4.3 断言实战

javascript 复制代码
// 密码强度验证:至少包含大写、小写、数字
const strongPassword = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/;
strongPassword.test('Abc12345');  // true
strongPassword.test('abc12345');  // false,缺少大写

// 千分位格式化
const addCommas = (num) => {
  return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
};
addCommas(1234567);  // '1,234,567'

// 提取不在引号内的内容
const regex = /\w+(?=(?:[^"]*"[^"]*")*[^"]*$)/g;

五、JavaScript正则API

5.1 RegExp方法

javascript 复制代码
// test() - 测试是否匹配
/\d+/.test('abc123');  // true

// exec() - 执行匹配,返回详细信息
const regex = /(\d{4})-(\d{2})-(\d{2})/;
const result = regex.exec('2024-01-15');
// result[0] = '2024-01-15'
// result[1] = '2024'
// result.index = 0
// result.input = '2024-01-15'

// 全局匹配迭代
const globalRegex = /\d+/g;
let match;
while ((match = globalRegex.exec('a1b2c3')) !== null) {
  console.log(match[0], match.index);
}
// '1' 1
// '2' 3
// '3' 5

5.2 String方法

javascript 复制代码
// match() - 匹配
'hello world'.match(/\w+/);   // ['hello']
'hello world'.match(/\w+/g);  // ['hello', 'world']

// matchAll() - 返回迭代器(ES2020)
const matches = 'a1b2c3'.matchAll(/(\w)(\d)/g);
for (const match of matches) {
  console.log(match[0], match[1], match[2]);
}
// 'a1' 'a' '1'
// 'b2' 'b' '2'
// 'c3' 'c' '3'

// search() - 返回首次匹配位置
'hello world'.search(/world/);  // 6
'hello world'.search(/xyz/);    // -1

// replace() - 替换
'hello world'.replace(/world/, 'regex');  // 'hello regex'
'aaa'.replace(/a/g, 'b');                 // 'bbb'

// 替换函数
'hello world'.replace(/\w+/g, (match) => {
  return match.toUpperCase();
});
// 'HELLO WORLD'

// 替换函数参数
'2024-01-15'.replace(
  /(\d{4})-(\d{2})-(\d{2})/,
  (match, year, month, day) => {
    return `${day}/${month}/${year}`;
  }
);
// '15/01/2024'

// replaceAll() - 替换所有(ES2021)
'aaa'.replaceAll('a', 'b');  // 'bbb'

// split() - 分割
'a,b;c|d'.split(/[,;|]/);  // ['a', 'b', 'c', 'd']
'a1b2c3'.split(/\d/);      // ['a', 'b', 'c', '']

5.3 常用技巧

javascript 复制代码
// 转义特殊字符
function escapeRegExp(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

// 动态创建正则
function createSearchRegex(keyword) {
  const escaped = escapeRegExp(keyword);
  return new RegExp(escaped, 'gi');
}

// 高亮搜索关键词
function highlightKeyword(text, keyword) {
  const regex = createSearchRegex(keyword);
  return text.replace(regex, '<mark>$&</mark>');
}

highlightKeyword('Hello World', 'world');
// 'Hello <mark>World</mark>'

六、实战案例大全

6.1 表单验证

javascript 复制代码
// 手机号(中国大陆)
const phoneRegex = /^1[3-9]\d{9}$/;

// 邮箱
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;

// 身份证号
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]$/;

// URL
const urlRegex = /^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([\/\w .-]*)*\/?$/;

// IP地址
const ipRegex = /^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/;

// 密码强度(8-20位,包含大小写字母和数字)
const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,20}$/;

// 中文
const chineseRegex = /^[\u4e00-\u9fa5]+$/;

// 用户名(字母开头,允许字母数字下划线,4-16位)
const usernameRegex = /^[a-zA-Z][a-zA-Z0-9_]{3,15}$/;

// 银行卡号(16-19位数字)
const bankCardRegex = /^\d{16,19}$/;

// 邮政编码
const postalCodeRegex = /^[1-9]\d{5}$/;

6.2 数据提取

javascript 复制代码
// 提取URL中的参数
function getUrlParams(url) {
  const params = {};
  const regex = /[?&]([^=&#]+)=([^&#]*)/g;
  let match;
  
  while ((match = regex.exec(url)) !== null) {
    params[match[1]] = decodeURIComponent(match[2]);
  }
  
  return params;
}

getUrlParams('https://example.com?name=john&age=25');
// { name: 'john', age: '25' }

// 提取HTML标签内容
function extractTagContent(html, tagName) {
  const regex = new RegExp(`<${tagName}[^>]*>([\\s\\S]*?)<\\/${tagName}>`, 'gi');
  const matches = [];
  let match;
  
  while ((match = regex.exec(html)) !== null) {
    matches.push(match[1].trim());
  }
  
  return matches;
}

extractTagContent('<p>Hello</p><p>World</p>', 'p');
// ['Hello', 'World']

// 提取所有链接
function extractLinks(html) {
  const regex = /href=["']([^"']+)["']/gi;
  const links = [];
  let match;
  
  while ((match = regex.exec(html)) !== null) {
    links.push(match[1]);
  }
  
  return links;
}

// 提取日期
function extractDates(text) {
  const regex = /\d{4}[-/年]\d{1,2}[-/月]\d{1,2}日?/g;
  return text.match(regex) || [];
}

extractDates('会议时间:2024-01-15 和 2024/02/20');
// ['2024-01-15', '2024/02/20']

6.3 文本处理

javascript 复制代码
// 去除HTML标签
function stripHtml(html) {
  return html.replace(/<[^>]*>/g, '');
}

stripHtml('<p>Hello <b>World</b></p>');
// 'Hello World'

// 驼峰转下划线
function camelToSnake(str) {
  return str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`);
}

camelToSnake('getUserName');  // 'get_user_name'

// 下划线转驼峰
function snakeToCamel(str) {
  return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
}

snakeToCamel('get_user_name');  // 'getUserName'

// 首字母大写
function capitalize(str) {
  return str.replace(/\b\w/g, letter => letter.toUpperCase());
}

capitalize('hello world');  // 'Hello World'

// 压缩空白字符
function compressWhitespace(str) {
  return str.replace(/\s+/g, ' ').trim();
}

compressWhitespace('  hello   world  ');  // 'hello world'

// 格式化数字(千分位)
function formatNumber(num) {
  return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}

formatNumber(1234567.89);  // '1,234,567.89'

// 脱敏处理
function maskPhone(phone) {
  return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
}

maskPhone('13812345678');  // '138****5678'

function maskEmail(email) {
  return email.replace(/(.{2}).*(@.*)/, '$1***$2');
}

maskEmail('example@gmail.com');  // 'ex***@gmail.com'

function maskIdCard(idCard) {
  return idCard.replace(/(\d{6})\d{8}(\d{4})/, '$1********$2');
}

maskIdCard('110101199001011234');  // '110101********1234'

6.4 代码处理

javascript 复制代码
// 提取注释
function extractComments(code) {
  const singleLine = code.match(/\/\/.*$/gm) || [];
  const multiLine = code.match(/\/\*[\s\S]*?\*\//g) || [];
  return [...singleLine, ...multiLine];
}

// 移除注释
function removeComments(code) {
  return code
    .replace(/\/\/.*$/gm, '')           // 单行注释
    .replace(/\/\*[\s\S]*?\*\//g, '');  // 多行注释
}

// 提取函数名
function extractFunctionNames(code) {
  const regex = /function\s+(\w+)|(\w+)\s*=\s*(?:async\s*)?\(|(\w+)\s*:\s*(?:async\s*)?\(/g;
  const names = [];
  let match;
  
  while ((match = regex.exec(code)) !== null) {
    names.push(match[1] || match[2] || match[3]);
  }
  
  return names.filter(Boolean);
}

// 提取import语句
function extractImports(code) {
  const regex = /import\s+(?:{[^}]+}|\w+|\*\s+as\s+\w+)\s+from\s+['"]([^'"]+)['"]/g;
  const imports = [];
  let match;
  
  while ((match = regex.exec(code)) !== null) {
    imports.push(match[1]);
  }
  
  return imports;
}

6.5 日志分析

javascript 复制代码
// 解析Nginx日志
function parseNginxLog(line) {
  const regex = /^(\S+) - - \[([^\]]+)\] "(\w+) ([^"]+)" (\d+) (\d+)/;
  const match = line.match(regex);
  
  if (match) {
    return {
      ip: match[1],
      time: match[2],
      method: match[3],
      url: match[4],
      status: parseInt(match[5]),
      size: parseInt(match[6])
    };
  }
  
  return null;
}

// 提取错误日志
function extractErrors(logs) {
  const regex = /\[ERROR\]\s*(.+)/gi;
  return logs.match(regex) || [];
}

// 统计IP访问次数
function countIpVisits(logs) {
  const ipRegex = /^(\d{1,3}\.){3}\d{1,3}/gm;
  const ips = logs.match(ipRegex) || [];
  
  return ips.reduce((acc, ip) => {
    acc[ip] = (acc[ip] || 0) + 1;
    return acc;
  }, {});
}

📊 正则表达式速查表

语法 说明 示例
. 任意字符 a.c 匹配 abc
\d 数字 \d+ 匹配 123
\w 单词字符 \w+ 匹配 abc_123
\s 空白字符 \s+ 匹配空格
^ 开头 ^hello
$ 结尾 world$
* 0次或多次 a*
+ 1次或多次 a+
? 0次或1次 a?
{n,m} n到m次 a{2,4}
[abc] 字符类 [aeiou]
[^abc] 否定字符类 [^0-9]
(...) 捕获分组 (\d+)
(?:...) 非捕获分组 (?:\d+)
(?=...) 正向先行断言 \d+(?=元)
(?!...) 负向先行断言 \d+(?!元)
` `

💡 总结

正则表达式核心要点:

  1. 掌握基础语法:字符类、量词、边界
  2. 理解分组引用:捕获分组、反向引用
  3. 灵活使用断言:先行断言、后行断言
  4. 熟悉JS API:test、exec、match、replace
  5. 贪婪与非贪婪:理解匹配模式
  6. 实战积累:表单验证、数据提取、文本处理

正则表达式是开发者必备技能,熟练掌握能大幅提升开发效率!


💬 如果这篇文章对你有帮助,欢迎点赞收藏!有问题欢迎在评论区讨论~

相关推荐
小白学大数据20 小时前
百科词条结构化抓取:Java 正则表达式与 XPath 解析对比
java·开发语言·爬虫·正则表达式
烛阴1 天前
C# 正则表达式(5):前瞻/后顾(Lookaround)——零宽断言做“条件校验”和“精确提取”
前端·正则表达式·c#
智航GIS2 天前
8.13 正则表达式
数据库·mysql·正则表达式
上去我就QWER5 天前
你了解正则表达式中“?”的作用吗?
正则表达式
qq_317620315 天前
第09章-标准库与常用模块
正则表达式·标准库·collections模块·数据序列化·时间处理
玄同7657 天前
Python 异常捕获与处理:从基础语法到工程化实践的万字深度指南
开发语言·人工智能·python·自然语言处理·正则表达式·nlp·知识图谱
zhuzhihongNO17 天前
Java正则表达式持续更新
正则表达式·pattern.dotall·正则表达式贪婪模式·正则表达式惰性模式·java正则表达式
玄同7658 天前
Python 正则表达式:LLM 噪声语料的精准清洗
人工智能·python·自然语言处理·正则表达式·nlp·知识图谱·rag