正则表达式入门教程(长文讲解)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
前言
在编程和文本处理中,正则表达式(Regular Expression,简称 regex 或 regexp)是一种强大的工具,能帮助开发者高效地匹配、查找、替换和验证文本模式。无论是从日志文件中提取关键信息,还是验证用户输入的邮箱格式,正则表达式都能显著提升开发效率。然而,对许多编程初学者而言,正则表达式如同“神秘代码”,其符号和语法令人望而却步。本文将通过 正则表达式入门教程 的形式,以循序渐进的方式拆解其核心概念,并结合实际案例,帮助读者快速掌握这一技能。
基础语法解析:正则表达式如何“阅读”文本?
正则表达式可以看作是“文字版的乐高积木”——通过组合不同的符号和规则,构建出能匹配特定文本模式的“指令”。其基本构成包括普通字符、元字符和量词。
1. 普通字符:直接匹配
普通字符(如字母、数字、空格)在正则表达式中直接表示其本身。例如:
- 正则表达式
hello
会匹配字符串中的“hello”; - 正则表达式
2023
会匹配“2023”这样的年份。
2. 元字符:特殊功能符号
元字符是正则表达式的核心,它们像“开关”一样,改变匹配行为:
| 元字符 | 功能说明 | 示例 |
|--------|----------|------|
| .
| 匹配任意单个字符(除换行符外) | a.c
匹配 "abc"、"a2c",但不匹配 "ac" |
| ^
| 匹配字符串开头 | ^start
匹配以 "start" 开头的字符串 |
| $
| 匹配字符串结尾 | end$
匹配以 "end" 结尾的字符串 |
| |
| 表示“或”关系 | cat|dog
匹配 "cat" 或 "dog" |
3. 量词:控制匹配次数
量词定义字符或模式的重复次数,常见的包括:
*
:匹配前面的元素 零次或多次(如a*
匹配空字符串、"a"、"aa" 等);+
:匹配前面的元素 一次或多次(如a+
匹配 "a"、"aa",但不匹配空字符串);?
:匹配前面的元素 零次或一次(如a?
匹配空字符串或 "a");{n}
:精确匹配 n次(如a{3}
匹配 "aaa");{n,m}
:匹配 n到m次(如a{2,4}
匹配 "aa"、"aaa" 或 "aaaa")。
比喻说明:
想象量词是“贪吃的小怪兽”,*
是“能吃光所有食物”,而 ?
是“只吃一口或不吃”。例如:
a.*b
这条规则会匹配从“a”开始,到“b”结束之间的所有字符(如 "abc"、"a123b")。
元字符进阶:边界、字符集与转义
1. 字符集(Character Set):定义匹配范围
用 []
定义一个字符集,匹配其中任意一个字符。例如:
[abc]
匹配 "a"、"b" 或 "c";[0-9]
匹配任意数字(等价于\d
)。
否定字符集:[^abc]
匹配不在字符集中的字符。
2. 转义特殊字符:用反斜杠 \
若需匹配元字符本身(如匹配 .
或 *
),需用 \
转义。例如:
\.
匹配句号;\*
匹配星号。
3. 预定义字符类:简化复杂模式
正则表达式提供预定义字符类,例如:
\d
:匹配任意数字(等同于[0-9]
);\w
:匹配字母、数字或下划线(等同于[a-zA-Z0-9_]
);\s
:匹配空白字符(空格、换行、制表符等)。
案例演示:
验证一个字符串是否为 4 位纯数字的年份:
^\d{4}$
这条规则会匹配 "2023",但不会匹配 "202a" 或 "2023a"。
分组与捕获:提取文本片段
1. 捕获组:用 ()
围绕模式
分组可以将多个字符视为一个整体,并实现捕获功能。例如:
(cat|dog) is cute
此规则匹配 "cat is cute" 或 "dog is cute",且捕获“cat”或“dog”作为第一组。
2. 反向引用:引用已捕获的内容
在替换操作中,可通过 \n
(n为组号)引用捕获的内容。例如:
const str = 'apple and apple';
const result = str.replace(/(apple) and \1/, '$1 only');
// 结果:'apple only'
此处 \1
引用第一个捕获组(“apple”),实现替换重复内容。
3. 非捕获组:用 (?:...)
忽略捕获
若仅需分组而无需捕获,可用 (?:...)
:
\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12][0-9]|3[01])
此规则验证日期格式(如 "2023-09-15"),但不会保存中间的月份和日期。
进阶技巧:边界匹配与贪婪模式
1. 边界匹配:精确控制位置
-
单词边界
\b
:匹配单词的开始或结束位置。例如:\bhello\b
会匹配独立的 "hello",但不会匹配 "hello123" 或 "sayhello"。
-
非单词边界
\B
:与\b
相反,匹配非单词边界位置。
2. 贪婪与懒惰模式
默认情况下,量词是“贪婪”的,即尽可能匹配最长的字符串。例如:
<a>.*</a>
在匹配 "text1text2" 时,会匹配到第二个 "",导致范围过长。
懒惰模式通过 *?
、+?
等修饰符实现最小匹配:
<a>.*?</a>
此规则会正确匹配第一个 "..." 块。
实战案例:常见场景解析
案例1:验证邮箱格式
邮箱通常包含用户名、@ 符号和域名。正则表达式可设计为:
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
分步解释:
^
:匹配字符串开头;[a-zA-Z0-9._%+-]+
:匹配用户名(至少一个字符);@
:匹配 @ 符号;[a-zA-Z0-9.-]+
:匹配域名前缀;\.[a-zA-Z]{2,}$
:匹配顶级域名(如 .com、.org)。
案例2:提取文章中的日期
假设文本中包含日期格式如 "2023-09-15",正则表达式为:
\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])
此规则通过分组确保:
- 月份为 01-12;
- 日期为 01-31(需结合具体月份调整精确性)。
案例3:替换敏感词
若需将文本中的敏感词替换为星号,可使用:
text.replace(/(敏感词1|敏感词2)/g, (match) => '*'.repeat(match.length));
其中,g
标志表示全局替换。
常见问题与调试技巧
1. 正则表达式不匹配?检查这些点!
- 是否遗漏转义符?(如匹配
.
需写为\.
); - 量词是否过“贪婪”?尝试添加
?
转为懒惰模式; - 是否需要使用全局(
g
)或多行(m
)标志?
2. 在线工具辅助调试
推荐使用 regex101.com 或浏览器开发者工具,输入正则表达式和测试文本,实时查看匹配结果。
结论
正则表达式是一门需要“边学边练”的技能。通过本文的 正则表达式入门教程,我们系统梳理了其核心语法、进阶技巧及实际案例。从基础的字符匹配到复杂的分组捕获,正则表达式能显著提升文本处理的效率。
建议读者从简单场景入手(如验证手机号、提取 URL),逐步挑战复杂需求(如解析 HTML 结构)。同时,善用在线工具和调试技巧,能更快定位问题。掌握正则表达式后,你将解锁编程中更高效、优雅的解决方案。
编程之路永无止境,而正则表达式正是你工具箱中不可或缺的“瑞士军刀”。希望这篇入门教程能为你打开这扇门,未来继续探索更高级的主题(如反向引用、前瞻/后顾断言等),让正则表达式真正成为你的得力伙伴。