正则表达式 – 示例(保姆级教程)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

前言

在编程和数据处理中,正则表达式(Regular Expression)是一种强大的文本匹配工具,被广泛应用于字符串搜索、验证、替换等场景。对于编程初学者而言,它可能显得抽象难懂;而对中级开发者来说,深入掌握其核心语法和高级技巧可以显著提升开发效率。本文通过循序渐进的方式,结合具体示例,帮助读者理解正则表达式的基本原理和实际应用。

一、正则表达式的基础语法

1.1 什么是正则表达式?

正则表达式可以被理解为一种“通缉令”,它通过特定的符号组合,描述需要匹配的文本模式。例如,如果你想找到所有以 @ 符号开头、以 .com 结尾的字符串,正则表达式能快速完成这一任务。

1.2 基础元素:字符与字面量

正则表达式中最简单的模式是直接匹配字符。例如:

  • hello 匹配字符串中的“hello”;
  • 123 匹配数字序列“123”。

但有些字符具有特殊含义,称为元字符(如 .*+),需要通过转义符 \ 来表示其字面意义。例如:

import re  
pattern = r"\."  # 匹配实际的点字符"."  
text = "example.com"  
matches = re.findall(pattern, text)  
print(matches)  # 输出:["."]  

1.3 元字符的初步应用:.*

  • .(点号):匹配除换行符外的任意单个字符。
    例如,a.b 可以匹配 a1ba baXb,但不能匹配 aab
  • *(星号):匹配前一个字符的零次或多次出现。
    例如,a*b 匹配 b(零次 a)、ab(一次 a)、aaab(多次 a)。

示例代码(JavaScript)

const str = "aabbb";  
const regex = /a*b/;  
console.log(regex.test(str)); // 输出:true(匹配前两个 a 后的 b)  

二、元字符与特殊符号的进阶用法

2.1 字符集与字符范围:[][^]

  • 字符集 []:匹配括号内的任意一个字符。例如,[abc] 匹配 abc
    pattern = r"[0-9]"  # 匹配任意数字  
    text = "price: $12.99"  
    matches = re.findall(pattern, text)  
    print(matches)  # 输出:['1', '2', '9', '9']  
    
  • 否定字符集 [^]:匹配不在括号内的任意字符。例如,[^0-9] 匹配非数字字符。

2.2 量词的扩展:+?{n,m}

  • +:匹配前一个字符的一次或多次出现。
    例如,a+b 匹配 abaaab,但不匹配 b
  • ?:匹配前一个字符的零次或一次出现。
    例如,colou?r 匹配 color(美式拼写)或 colour(英式拼写)。
  • {n,m}:匹配前一个字符的最少 n 次、最多 m 次出现。
    例如,a{2,4}b 匹配 aabaaabaaaab

2.3 锚点:^$

  • ^:匹配字符串的开头。例如,^hello 只匹配以 hello 开头的字符串。
  • $:匹配字符串的结尾。例如,\.com$ 只匹配以 .com 结尾的字符串。

案例:邮箱验证

// 匹配简单邮箱格式:以字母开头,包含 @ 符号,以 .com 结尾  
const emailRegex = /^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.(com|net)$/;  
console.log(emailRegex.test("test@example.com")); // true  
console.log(emailRegex.test("test@domain")); // false(缺少后缀)  

三、常见正则表达式模式与实际案例

3.1 电话号码验证

假设需要验证中国手机号码(11 位数字,以 131518 等开头):

phone_pattern = r"^1[3-9]\d{9}$"  
text = "13812345678"  
print(re.fullmatch(phone_pattern, text))  # 匹配成功  

3.2 URL 解析

提取 URL 中的协议和路径:

const url = "https://example.com/path/to/page?query=123";  
const regex = /^(\w+):\/\/([^\/]+)(.*)/;  
const matches = url.match(regex);  
console.log(matches);  
// 输出:["https://example.com/path/to/page", "https", "example.com", "/path/to/page"]  
  • 解释
    • (\w+) 捕获协议(如 httphttps);
    • ([^\/]+) 捕获域名;
    • (.*) 捕获路径和查询参数。

3.3 文本替换:删除 HTML 标签

使用正则表达式去除字符串中的 HTML 标签:

text = "<p>这是段落。</p><div>内容</div>";  
clean_text = re.sub(r"<.*?>", "", text);  
print(clean_text);  # 输出:这是段落。内容  

注意:此示例为简化版,实际处理复杂 HTML 需使用专用库(如 BeautifulSoup)。

四、高级技巧与常见陷阱

4.1 分组与捕获

使用 () 对匹配结果进行分组,便于后续引用。例如,提取邮箱中的用户名和域名:

const email = "user@example.com";  
const regex = /(.+)@(.+)/;  
const [, username, domain] = email.match(regex);  
console.log(username); // user  
console.log(domain); // example.com  

4.2 非贪婪匹配:*?+?

默认量词是“贪婪的”,会尽可能多匹配字符。添加 ? 可以改为非贪婪模式:

text = "<div>内容1</div><div>内容2</div>";  
greedy = re.search(r"<div>(.*?)</div>", text);  
print(greedy.group(1));  # 输出:内容1</div><div>内容2  

non_greedy = re.search(r"<div>(.*?)</div>", text, re.DOTALL);  
print(non_greedy.group(1));  # 输出:内容1  

4.3 回溯与性能优化

复杂的正则表达式可能导致“回溯爆炸”(Backtracking Catastrophe),显著降低性能。例如,模式 .*a.*b 在处理长字符串时可能因多次回溯而崩溃。
解决方案

  • 使用非捕获组 (?:...) 减少分组;
  • 避免不必要的重复模式。

4.4 跨语言兼容性

不同编程语言对正则表达式的实现略有差异。例如:

  • Python 中需使用 re 模块;
  • JavaScript 直接支持正则表达式字面量 /pattern/;
  • Java 需通过 PatternMatcher 类操作。

案例:密码强度验证

// 验证密码:至少 8 位,含大写字母、小写字母、数字  
const passwordRegex = /^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,}$/;  
console.log(passwordRegex.test("Pass1234")); // true  
console.log(passwordRegex.test("pass")); // false  

五、结论

正则表达式是一门需要“边学边练”的技术。通过理解基础语法、掌握元字符的含义、结合实际案例练习,开发者可以逐步提升其使用能力。无论是验证用户输入、解析日志文件,还是自动化文本处理,正则表达式都能提供高效且灵活的解决方案。

关键点回顾

  • 字符、元字符与量词的组合构成正则表达式的核心;
  • 锚点和分组帮助精准定位目标文本;
  • 避免陷阱(如贪婪匹配)是优化性能的关键。

通过持续实践和查阅文档,正则表达式将成为你工具箱中不可或缺的利器。

最新发布