正则表达式从入门到精通(完全指南)

 更新时间:2026年08月27日 09:26:34   作者:落魄大学生之流水线上谋生计  
正则表达式是一种用于匹配字符串中字符组合的模式,它由普通字符和特殊字符(元字符)组成,可以用来验证、搜索、替换文本,本文给大家介绍正则表达式从入门到精通,感兴趣的朋友一起看看吧

一、什么是正则表达式?

正则表达式(Regular Expression,简称 Regex)是一种用于匹配字符串中字符组合的模式。它由普通字符和特殊字符(元字符)组成,可以用来验证、搜索、替换文本。

🎯 核心价值:用一行代码完成复杂的字符串处理任务

二、基础语法

2.1 普通字符

字符说明示例
abc匹配字符串 “abc”hello 匹配 hello
123匹配数字123abc 匹配 123
\转义字符\. 匹配实际的点号

2.2 元字符(Metacharacters)

元字符说明示例匹配结果
.匹配任意单个字符(除换行符)h.that, hot, h t
^匹配字符串开头^Hello以 Hello 开头的字符串
$匹配字符串结尾world$以 world 结尾的字符串
|或运算符cat|dogcat 或 dog
()分组捕获(ab)+匹配一个或多个 ab
[]字符集[abc]匹配 a、b 或 c

2.3 量词(Quantifiers)

量词说明示例匹配次数
*零次或多次ab*cac, abc, abbc…
+一次或多次ab+cabc, abbc…(不匹配 ac)
?零次或一次colou?rcolor, colour
{n}恰好 n 次a{3}aaa
{n,}至少 n 次a{2,}aa, aaa, aaaa…
{n,m}n 到 m 次a{2,4}aa, aaa, aaaa

2.4 字符类(Character Classes)

说明示例
\d数字 [0-9]\d+ 匹配 123
\D非数字\D+ 匹配 abc
\w单词字符 [a-zA-Z0-9_]\w+ 匹配 hello_123
\W非单词字符\W+ 匹配 @#$
\s空白字符(空格、制表符、换行符)\s+ 匹配多个空格
\S非空白字符\S+ 匹配 hello
\b单词边界\bword\b 精确匹配 word
\B非单词边界\Bword\B 匹配 swordfish 中的 word

2.5 反义(Negations)

说明示例
[^abc]不匹配 a、b、c[^0-9] 匹配非数字
[a-z]匹配小写字母[a-z]+ 匹配 hello
[A-Z]匹配大写字母[A-Z]+ 匹配 HELLO
[0-9]匹配数字[0-9]+ 匹配 12345

三、进阶语法

3.1 贪婪与非贪婪

模式说明示例
.*贪婪匹配(尽可能多).* in aabbcc 匹配 aabbcc
.*?非贪婪匹配(尽可能少).*? in aabbcc 匹配空字符串
.+?非贪婪匹配.+? in aabbcc 匹配 a
{n,m}?非贪婪量词a{2,4}? 匹配 aa

示例:

import re
html = '<p>Hello</p><p>World</p>'
# 贪婪匹配(错误)
re.findall(r'<p>.*</p>', html)  # ['<p>Hello</p><p>World</p>']
# 非贪婪匹配(正确)
re.findall(r'<p>.*?</p>', html)  # ['<p>Hello</p>', '<p>World</p>']

3.2 前瞻与后顾(Lookaround)

类型语法说明
正向前瞻(?=pattern)匹配后面跟着 pattern 的位置
负向前瞻(?!pattern)匹配后面不跟着 pattern 的位置
正向后顾(?<=pattern)匹配前面是 pattern 的位置
负向后顾(?<!pattern)匹配前面不是 pattern 的位置

示例:

import re
# 提取价格(不包含货币符号)
text = '价格:$100 和 ¥200'
# 正向前瞻
re.findall(r'(?<=\$)\d+', text)   # ['100']
re.findall(r'(?<=¥)\d+', text)    # ['200']
# 负向前瞻:匹配后面不跟数字的单词
re.findall(r'\b\w+(?!\d)', 'abc123 def456')  # ['abc', 'def']

3.3 分组与捕获

import re
# 基本分组
pattern = r'(\d{3})-(\d{4})'
text = '电话:123-4567'
match = re.search(pattern, text)
if match:
    print(match.group(0))  # 123-4567(完整匹配)
    print(match.group(1))  # 123(第一组)
    print(match.group(2))  # 4567(第二组)
    print(match.groups())   # ('123', '4567')

3.4 命名分组

import re
# 命名分组 (?P<name>pattern)
pattern = r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'
text = '日期:2024-01-15'
match = re.search(pattern, text)
if match:
    print(match.group('year'))   # 2024
    print(match.group('month'))  # 01
    print(match.group('day'))    # 15

3.5 非捕获分组

import re
# 非捕获分组 (?:pattern) - 不保存匹配结果
pattern = r'(?:http|https)://(\S+)'
text = '访问 https://example.com'
match = re.search(pattern, text)
if match:
    print(match.group(0))  # https://example.com
    print(match.group(1))  # example.com(只有捕获组)

四、Python re 模块详解

4.1 常用函数

函数说明返回值
re.match()从字符串开头匹配Match 对象或 None
re.search()搜索整个字符串第一个匹配的 Match 对象
re.findall()查找所有匹配列表
re.finditer()查找所有匹配迭代器
re.sub()替换匹配的字符串新字符串
re.split()按模式分割字符串列表
re.compile()编译正则表达式Pattern 对象

4.2 使用示例

import re
# 1. match - 从开头匹配
re.match(r'\d+', '123abc')    # Match: '123'
re.match(r'\d+', 'abc123')    # None(不是开头)
# 2. search - 搜索第一个匹配
re.search(r'\d+', 'abc123def')  # Match: '123'
# 3. findall - 查找所有匹配
re.findall(r'\d+', 'a1b2c3')   # ['1', '2', '3']
# 4. sub - 替换
re.sub(r'\d+', '*', 'a1b2c3')  # 'a*b*c*'
re.sub(r'(\w+)', r'\1\1', 'ab')  # 'aabb'(重复单词)
# 5. split - 分割
re.split(r'\s+', 'hello world foo')  # ['hello', 'world', 'foo']
re.split(r'[;|,]', 'a;b,c|d')       # ['a', 'b', 'c', 'd']
# 6. compile - 编译复用
email_pattern = re.compile(r'[\w.]+@[\w.]+\.\w+')
email_pattern.findall('test@example.com and info@test.org')
# ['test@example.com', 'info@test.org']

4.3 编译标志(Flags)

标志说明使用方式
re.IGNORECASE忽略大小写re.IGNORECASEre.I
re.MULTILINE多行模式(^ $ 匹配每行)re.MULTILINEre.M
re.DOTALL点号匹配换行符re.DOTALLre.S
re.VERBOSE允许注释和空格re.VERBOSEre.X
re.UNICODEUnicode 模式re.UNICODEre.U
import re
# 忽略大小写
re.findall(r'hello', 'Hello HELLO hello', re.I)  # ['Hello', 'HELLO', 'hello']
# 多行模式
text = 'line1\nline2\nline3'
re.findall(r'^\w+', text, re.M)  # ['line1', 'line2', 'line3']
# 点号匹配换行符
re.findall(r'.+', 'line1\nline2', re.S)  # ['line1\nline2']
# 详细的正则(忽略空格和注释)
phone = re.compile(r'''
    (\d{3,4})     # 区号
    [-\s]?        # 可选分隔符
    (\d{7,8})     # 电话号码
''', re.VERBOSE)

五、爬虫实战常用正则

5.1 URL 提取

import re
# 匹配 HTTP/HTTPS URL
url_pattern = r'https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+[^\s]*'
text = '请访问 https://example.com/path?query=1 或 http://test.org'
re.findall(url_pattern, text)
# ['https://example.com/path?query=1', 'http://test.org']
# 匹配相对 URL
relative_pattern = r'href=["\']([^"\']+)["\']'
html = '<a href="/page1" rel="external nofollow" >Link</a>'
re.findall(relative_pattern, html)  # ['/page1']

5.2 邮箱提取

import re
# 基本邮箱验证
email_pattern = r'[\w.+-]+@[\w-]+\.[\w.-]+'
# 更严格的邮箱验证
strict_email = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
emails = """
联系方式:
- 简单邮箱:test@example.com
- 公司邮箱:user.name@company.co.uk
- 个人邮箱:user+tag@gmail.com
"""
re.findall(email_pattern, emails)
# ['test@example.com', 'user.name@company.co.uk', 'user+tag@gmail.com']

5.3 手机号提取

import re
# 中国大陆手机号
phone_pattern = r'1[3-9]\d{9}'
# 带格式的手机号
formatted_phone = r'1[3-9]\d{1}[-\s]?\d{4}[-\s]?\d{4}'
text = '联系我:13812345678 或 139-1234-5678'
re.findall(phone_pattern, text)  # ['13812345678', '13912345678']

5.4 IP 地址提取

import re
# 基本 IPv4
ip_pattern = r'\b(?:\d{1,3}\.){3}\d{1,3}\b'
# 严格的 IPv4 验证
strict_ip = r'^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$'
log = '访问来自 192.168.1.100 和 10.0.0.1'
re.findall(ip_pattern, log)  # ['192.168.1.100', '10.0.0.1']

5.5 HTML 内容提取

import re
# 提取标题
title_pattern = r'<title>(.*?)</title>'
# 提取 meta 描述
meta_pattern = r'<meta\s+name=["\']description["\']\s+content=["\'](.*?)["\']'
# 提取所有文本(去标签)
text_pattern = r'<[^>]+>'
html = '''
<html>
<head><title>网页标题</title></head>
<body>
  <h1>主标题</h1>
  <p>段落内容</p>
</body>
</html>
'''
re.findall(title_pattern, html)  # ['网页标题']
re.sub(text_pattern, '', html)   # '网页标题主标题段落内容'

5.6 数据清洗

import re
# 去除多余空白
clean = r'\s+'
text = '  hello   world  \n  foo  '
re.sub(clean, ' ', text.strip())  # 'hello world foo'
# 去除 HTML 实体
entity_pattern = r'&[a-zA-Z]+;|&#\d+;'
text = '价格:100<200 & 300'
re.sub(entity_pattern, lambda m: {
    '<': '<', '>': '>', '&': '&'
}.get(m.group(), ''), text)
# 中文提取
chinese_pattern = r'[\u4e00-\u9fa5]+'
text = 'Hello 你好 World 世界'
re.findall(chinese_pattern, text)  # ['你好', '世界']

六、常用正则表达式速查表

6.1 验证类

# 手机号验证
r'^1[3-9]\d{9}$'
# 邮箱验证
r'^[\w.+-]+@[\w-]+\.[\w.-]+$'
# 身份证号验证(18位)
r'^[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 验证
r'^https?://[-\w.]+(?:/[-\w./]*)?$'
# IP 地址验证
r'^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$'

6.2 提取类

# 中文字符
r'[\u4e00-\u9fa5]+'
# 英文单词
r'\b[a-zA-Z]+\b'
# 数字(整数和小数)
r'-?\d+\.?\d*'
# 日期格式 YYYY-MM-DD
r'\d{4}[-/]\d{1,2}[-/]\d{1,2}'
# 时间格式 HH:MM:SS
r'\d{1,2}:\d{2}:\d{2}'
# Hex 颜色值
r'#(?:[0-9a-fA-F]{3}){1,2}\b'

6.3 替换类

# 压缩多个空格
r'\s+'
# HTML 标签
r'<[^>]+>'
# 中文标点转英文标点
r'[,。;:!?]'
# 全角转半角
r'[\uff01-\uff5e]'

七、性能优化技巧

7.1 编译正则

import re
# ❌ 不推荐:每次调用都重新编译
def find_emails(text):
    return re.findall(r'[\w.+-]+@[\w-]+\.[\w.-]+', text)
# ✅ 推荐:编译一次复用
EMAIL_PATTERN = re.compile(r'[\w.+-]+@[\w-]+\.[\w.-]+')
def find_emails(text):
    return EMAIL_PATTERN.findall(text)

7.2 使用原始字符串

# ❌ 不推荐:需要双重转义
pattern = "\\d+\\.\\d+"
# ✅ 推荐:原始字符串
pattern = r'\d+\.\d+'

7.3 避免回溯

import re
# ❌ 容易产生回溯(灾难性回溯)
bad_pattern = r'(a+)+b'
# ✅ 更高效的写法
good_pattern = r'a+b'

7.4 使用非贪婪匹配

import re
html = '<div>content</div><div>more</div>'
# ❌ 贪婪匹配
re.findall(r'<div>.*</div>', html)  # ['<div>content</div><div>more</div>']
# ✅ 非贪婪匹配
re.findall(r'<div>.*?</div>', html)  # ['<div>content</div>', '<div>more</div>']

八、常见错误与调试

8.1 常见错误

错误原因解决方案
re.error: nothing to repeat量词前没有字符检查正则表达式
re.error: bad escape无效的转义序列使用原始字符串
匹配结果为空正则写错或模式不匹配逐步调试正则

8.2 调试技巧

import re
# 使用 re.VERBOSE 添加注释
pattern = re.compile(r'''
    ^                   # 字符串开头
    (?P<year>\d{4})     # 年
    -                   # 分隔符
    (?P<month>\d{2})    # 月
    -                   # 分隔符
    (?P<day>\d{2})      # 日
    $                   # 字符串结尾
''', re.VERBOSE)
# 在线调试工具
# https://regex101.com/
# https://debuggex.com/

九、总结

📋 正则表达式核心要点

  1. 基础元字符., ^, $, *, +, ?, [], (), \|
  2. 字符类\d, \w, \s 及其大写反义
  3. 量词*, +, ?, {n}, {n,}, {n,m}
  4. 贪婪与非贪婪.* vs .*?
  5. 分组捕获() 和命名分组 (?P<name>)
  6. 前瞻后顾(?=), (?!), (?<=), (?<!)

🎯 学习建议

  1. 从简单模式开始,逐步复杂化
  2. 使用在线工具(regex101.com)测试
  3. 先理解需求,再编写正则
  4. 避免过度使用,可读性很重要
  5. 注意性能,避免灾难性回溯

到此这篇关于正则表达式从入门到精通(完全指南)的文章就介绍到这了,更多相关正则表达式入门内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

最新评论