正则表达式从入门到精通

正则表达式从入门到精通教程

这个教程会通过三个阶段(入门、进阶、精通)带你逐步学习正则表达式,附带实战练习和如何逐步编写符合需求的正则表达式。


阶段 1:入门

1. 什么是正则表达式?

正则表达式(Regular Expression, regex)是一种用于字符串匹配和处理的模式描述语言,可以用来搜索、替换和验证字符串。


2. 必备基础概念

特殊符号
  • . : 匹配任意单个字符(除换行符)。
    • 示例:a.c 匹配 abc, a1c 等。
  • [] : 匹配字符集中的任意一个字符。
    • 示例:[abc] 匹配 a, b, c
  • - : 表示字符范围。
    • 示例:[a-z] 匹配所有小写字母。
  • \ : 转义符,用于匹配特殊字符本身。
    • 示例:\. 匹配点号 .
量词
  • * : 匹配前面的内容 0 次或多次。
    • 示例:a* 匹配 "", a, aaa
  • + : 匹配前面的内容 1 次或多次。
    • 示例:a+ 匹配 a, aa
  • ? : 匹配前面的内容 0 次或 1 次。
    • 示例:a? 匹配 "", a
  • {n} : 匹配前面的内容正好 n 次。
    • 示例:a{3} 匹配 aaa

3. 入门实战:用正则匹配简单的格式

任务:匹配一个简单的电话号码格式
  • 示例号码:123-456-7890
  • 步骤:
    1. 分析结构:由数字、短横线组成,格式是 三位数字-三位数字-四位数字
    2. 转换为正则:\d{3}-\d{3}-\d{4}
python 复制代码
import re

pattern = r"\d{3}-\d{3}-\d{4}"
text = "我的电话是 123-456-7890,请联系我。"
match = re.search(pattern, text)
if match:
    print("找到电话号码:", match.group())

阶段 2:进阶

1. 边界匹配

  • ^ : 匹配字符串的开头。
    • 示例:^hello 匹配以 hello 开头的字符串。
  • $ : 匹配字符串的结尾。
    • 示例:world$ 匹配以 world 结尾的字符串。
任务:验证字符串是否是邮箱格式
  • 示例邮箱:example@mail.com
  • 分析结构:
    • 开头是字母或数字,可能包含下划线、点号。
    • 接着是 @,后面是域名。
    • 域名部分由字母数字组成,最后是点加后缀。
  • 转换为正则:^\w+@\w+\.\w+$
python 复制代码
pattern = r"^\w+@\w+\.\w+$"
email = "example@mail.com"
if re.match(pattern, email):
    print("合法邮箱")
else:
    print("非法邮箱")

2. 分组与引用

分组用 () 表示,引用用 \数字 指代之前的分组。

任务:匹配重复的单词
  • 示例文本:hello hello world
  • 分析需求:
    • 匹配相邻两个完全相同的单词。
    • 转换为正则:\b(\w+)\s+\1\b
python 复制代码
pattern = r"\b(\w+)\s+\1\b"
text = "hello hello world"
match = re.search(pattern, text)
if match:
    print("找到重复单词:", match.group())

3. 实战练习:提取日期

  • 示例日期:2024-11-17
  • 分析需求:
    • 格式是 年-月-日
    • 年是四位数字,月和日是两位数字。
    • 转换为正则:(\d{4})-(\d{2})-(\d{2})
python 复制代码
pattern = r"(\d{4})-(\d{2})-(\d{2})"
date = "今天是 2024-11-17。"
match = re.search(pattern, date)
if match:
    year, month, day = match.groups()
    print(f"提取日期: 年={year}, 月={month}, 日={day}")

阶段 3:精通

1. 贪婪与懒惰模式

  • 默认是贪婪模式:尽可能多地匹配。
  • ? 转为懒惰模式:尽可能少地匹配。
任务:匹配 HTML 标签内容
  • 示例文本:<div>Hello</div><div>World</div>
  • 贪婪模式:<.*> 会匹配整个 <div>Hello</div><div>World</div>
  • 懒惰模式:<.*?> 会分别匹配 <div></div>
python 复制代码
pattern = r"<.*?>"
text = "<div>Hello</div><div>World</div>"
matches = re.findall(pattern, text)
print("匹配结果:", matches)

2. 高级应用:嵌套匹配

任务:匹配嵌套结构(如数学表达式)

正则表达式不能直接处理嵌套结构,但可以通过多步操作实现。

  • 示例文本:(a + (b - c))
  • 分析需求:
    • 提取匹配外层和内层括号。
  • 转换为正则:\([^()]*\)
python 复制代码
pattern = r"\([^()]*\)"
text = "(a + (b - c)) + (d / e)"
matches = re.findall(pattern, text)
print("匹配括号内容:", matches)

3. 动态构造正则表达式

使用 re.compile 动态创建正则表达式,支持多种标志。

python 复制代码
import re

flags = re.IGNORECASE | re.MULTILINE
pattern = re.compile(r"hello", flags)
text = "Hello world\nhello again"
matches = pattern.findall(text)
print("匹配结果:", matches)

总结:如何编写正则表达式?

  1. 分析目标结构:
  • 定位模式中的固定部分和可变部分。
  • 确定字符类型(数字、字母、特殊字符)。
  1. 逐步分解编写:
  • 从简单匹配入手,逐步增加复杂逻辑。
  1. 测试表达式:
  • 使用在线工具(如 Regex101)。
  1. 优化与调试:
  • 使用非贪婪模式或分组引用优化结果。

附:正则表达式一览表

1. 元字符(Metacharacters)

元字符是正则表达式的核心,用于匹配特定类型的字符或定义模式。

基本元字符:

元字符 作用 示例 匹配结果
. 匹配任意单个字符(除了换行符) a.c 匹配 abc, a1c
\ 转义符,用于匹配特殊字符本身 a\.c 匹配 a.c
^ 匹配字符串的开头 ^abc 匹配以 abc 开头的字符串
$ 匹配字符串的结尾 xyz$ 匹配以 xyz 结尾的字符串
* 匹配前一个字符 0 次或多次 a* 匹配 "", a, aaa
+ 匹配前一个字符 1 次或多次 a+ 匹配 a, aa 等,但不匹配 ""
? 匹配前一个字符 0 次或 1 次 a? 匹配 "", a
{n} 匹配前一个字符正好 n 次 a{3} 匹配 aaa
{n,} 匹配前一个字符至少 n 次 a{2,} 匹配 aa, aaa
{n,m} 匹配前一个字符至少 n 次,至多 m 次 a{2,4} 匹配 aa, aaa, aaaa

字符集和范围:

元字符 作用 示例 匹配结果
[] 匹配括号内任意字符 [abc] 匹配 a, b, c
[^] 匹配不在括号内的字符 [^abc] 匹配除 a, b, c 以外的字符
- 指定字符范围 [a-z] 匹配 az 的任意小写字母

预定义字符集:

表达式 作用 示例 匹配结果
\d 匹配任意数字(0-9) \d+ 匹配 123, 4
\D 匹配任意非数字 \D+ 匹配 abc, !@#
\w 匹配任意单词字符(字母、数字或下划线) \w+ 匹配 abc, a1_
\W 匹配任意非单词字符 \W+ 匹配 @#$
\s 匹配任意空白字符(空格、制表符等) \s+ 匹配空格、换行符等
\S 匹配任意非空白字符 \S+ 匹配 abc, 123

2. 匹配模式(Greedy vs Lazy)

正则表达式默认是贪婪模式(尽可能多地匹配),但可以通过 ? 使其变为非贪婪模式(尽可能少地匹配)。

表达式 作用 示例 匹配结果
.* 贪婪:匹配尽可能多的字符 <.*> 匹配整个 <html><body>
.*? 非贪婪:匹配尽可能少的字符 <.*?> 分别匹配 <html><body>

3. 分组与引用

表达式 作用 示例 匹配结果
() 定义一个组 (abc)+ 匹配 abc, abcabc
(?:...) 非捕获组,不保存匹配结果 (?:abc)+ 匹配但不保存组
\n 引用第 n 个捕获组 (a)(b)\1\2 匹配 abab

4. 边界匹配

表达式 作用 示例 匹配结果
\b 匹配单词边界 \bword\b 匹配 word ,但不匹配 sword
\B 匹配非单词边界 \Bword\B 匹配 sworded 中的 word

5. 标志(Flags)

标志修改正则表达式的行为:

标志 作用 示例
re.IGNORECASE / re.I 忽略大小写 re.match("abc", "ABC", re.I)
re.DOTALL / re.S . 匹配换行符 re.match("a.b", "a\nb", re.S)
re.MULTILINE / re.M 多行模式,^$ 匹配每一行 re.match("^abc$", "abc\ndef", re.M)

6. 常见正则表达式例子

表达式 匹配内容
^\d{4}-\d{2}-\d{2}$ 日期格式:YYYY-MM-DD
\w+@\w+\.\w+ 电子邮件地址
https?://\S+ 匹配 URL
\d{3}-\d{3}-\d{4} 电话号码:123-456-7890
相关推荐
运维小贺1 天前
Nginx常用的模块
运维·nginx·正则表达式
Viooocc2 天前
正则表达式
正则表达式
vvilkim2 天前
开发中常用的正则表达式规则与应用
正则表达式
林深的林3 天前
正则表达式(1)
正则表达式
ThisIsClark4 天前
【玩转正则表达式】正则表达式常用语法汇总
正则表达式
ThisIsClark4 天前
【玩转正则表达式】替换与正则表达式的结合
正则表达式
浪九天5 天前
Java常用正则表达式(身份证号、邮箱、手机号)格式校验
java·开发语言·正则表达式
ThisIsClark5 天前
【玩转正则表达式】将正则表达式中的分组(group)与替换进行结合使用
数据库·mysql·正则表达式
小张-森林人8 天前
Oracle 字符串分割革命:正则表达式与 Lateral Join 的优雅解法
数据库·oracle·正则表达式
Lojarro8 天前
正则表达式
正则表达式