1. Python正则表达式入门指南
正则表达式(Regular Expression,简称re)是处理字符串的强大工具,它使用特定语法规则来描述字符串模式。作为一名Python开发者,掌握正则表达式能极大提升文本处理效率。本文将带你从零开始系统学习Python中的正则表达式应用。
1.1 正则表达式基础概念
正则表达式本质上是一个特殊的字符序列,它能帮助我们检查字符串是否与某种模式匹配。在Python中,我们通过re模块来使用正则表达式功能。
正则表达式具有以下特点:
- 跨语言通用性:不仅Python支持,Java、JavaScript、PHP、Go等主流语言都内置正则表达式支持
- 规则明确:通过特定元字符和语法规则定义匹配模式
- 功能强大:能实现复杂的字符串查找、替换、分割等操作
提示:学习正则表达式的核心是理解各种元字符的含义和组合方式,而不是死记硬背所有规则。实际开发中遇到复杂需求时,可以随时查阅文档或搜索解决方案。
1.2 Python正则表达式基本使用步骤
在Python中使用正则表达式通常遵循以下三步:
python复制# 1. 导入re模块
import re
# 2. 使用正则函数进行匹配
result = re.match(r'正则模式', '待匹配字符串')
# 3. 处理匹配结果
if result:
print(result.group())
else:
print('匹配失败')
Python的re模块提供了多个常用函数:
match():从字符串起始位置匹配search():扫描整个字符串查找匹配findall():返回所有匹配的子串sub():字符串替换split():按模式分割字符串
2. 正则表达式核心语法详解
2.1 匹配单个字符的元字符
正则表达式提供了多种匹配单个字符的方式:
| 元字符 | 说明 | 等价表示 | 示例 |
|---|---|---|---|
. |
匹配任意1个字符(除换行符\n) | - | a.c匹配"abc"、"a c"等 |
\d |
匹配数字 | [0-9] |
a\d匹配"a1"、"a9"等 |
\D |
匹配非数字 | [^0-9] |
a\D匹配"aa"、"a!"等 |
\w |
匹配单词字符(字母、数字、下划线、汉字) | [a-zA-Z0-9_] |
\w\w匹配"ab"、"a1"等 |
\W |
匹配非单词字符 | [^\w] |
\W\W匹配"!!"、"@#"等 |
\s |
匹配空白字符(空格、制表符等) | [\t\n\r\f\v] |
a\sb匹配"a b"、"a\tb"等 |
\S |
匹配非空白字符 | [^\s] |
\S\S匹配"ab"、"1@"等 |
字符集匹配:
[abc]:匹配a、b或c中的任意一个字符[^abc]:匹配除了a、b、c之外的任意字符[a-z]:匹配任意小写字母[A-Z0-9]:匹配大写字母或数字
2.2 匹配多个字符的量词
量词用于指定前面元素的匹配次数:
| 量词 | 说明 | 示例 |
|---|---|---|
* |
匹配0次或多次 | a*匹配""、"a"、"aa"等 |
+ |
匹配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" |
2.3 位置匹配
| 元字符 | 说明 | 示例 |
|---|---|---|
^ |
匹配字符串开头 | ^abc匹配以"abc"开头的字符串 |
$ |
匹配字符串结尾 | xyz$匹配以"xyz"结尾的字符串 |
\b |
匹配单词边界 | \bfoo\b匹配独立的"foo"单词 |
2.4 分组与捕获
分组是正则表达式中非常强大的功能:
python复制import re
# 基本分组
result = re.match(r'(\d{3})-(\d{4})', '010-1234')
if result:
print(result.group(1)) # 输出: 010
print(result.group(2)) # 输出: 1234
# 命名分组
result = re.match(r'(?P<area>\d{3})-(?P<number>\d{4})', '010-1234')
if result:
print(result.group('area')) # 输出: 010
print(result.group('number')) # 输出: 1234
分组引用:
\n:引用第n个分组(n为数字)(?P=name):引用命名分组
3. 正则表达式实战应用
3.1 手机号验证
中国手机号验证规则:
- 长度11位
- 纯数字
- 第1位为1
- 第2位为3-9
python复制import re
def validate_phone(phone):
pattern = r'^1[3-9]\d{9}$'
return bool(re.match(pattern, phone))
# 测试
print(validate_phone('13812345678')) # True
print(validate_phone('12812345678')) # False(第二位不符合)
print(validate_phone('138123456789')) # False(长度超长)
3.2 邮箱验证
常见邮箱验证规则:
- 用户名部分:4-20位字母、数字或下划线
- @符号
- 域名部分:主流邮箱服务商
- 顶级域名:.com/.cn等
python复制import re
def validate_email(email):
pattern = r'^[a-zA-Z0-9_]{4,20}@(163|126|qq|gmail)\.(com|cn|net)$'
return bool(re.match(pattern, email))
# 测试
print(validate_email('test@163.com')) # True
print(validate_email('test@gmail.com')) # True
print(validate_email('a@qq.com')) # False(用户名太短)
3.3 HTML标签匹配
HTML标签匹配需要考虑:
- 开始标签和结束标签配对
- 自闭合标签
- 标签属性
python复制import re
# 匹配成对标签
html = '<div><h1>标题</h1></div>'
pattern = r'<([a-zA-Z]+)>.*</\1>'
print(re.match(pattern, html).group()) # 输出: <div><h1>标题</h1></div>
# 匹配自闭合标签
html = '<img src="image.jpg" />'
pattern = r'<[a-zA-Z]+\s.*?/>'
print(re.match(pattern, html).group()) # 输出: <img src="image.jpg" />
3.4 数据提取
从字符串中提取特定格式的数据:
python复制import re
# 提取QQ号
text = '联系方式:QQ:123456,电话:13800138000'
pattern = r'QQ:(\d{5,11})'
result = re.search(pattern, text)
if result:
print(result.group(1)) # 输出: 123456
# 提取日期
text = '日期:2023-08-15,时间:14:30'
pattern = r'(\d{4})-(\d{2})-(\d{2})'
year, month, day = re.search(pattern, text).groups()
print(f'{year}年{month}月{day}日') # 输出: 2023年08月15日
4. 正则表达式高级技巧与性能优化
4.1 编译正则表达式
对于需要重复使用的正则模式,建议先编译:
python复制import re
# 未编译方式
result = re.match(r'\d+', '123abc')
# 编译后方式(性能更好)
pattern = re.compile(r'\d+')
result = pattern.match('123abc')
提示:当正则表达式会被多次使用时,编译可以显著提高性能。根据测试,编译后的正则表达式匹配速度能提升2-5倍。
4.2 非贪婪匹配
默认情况下,量词是"贪婪"的,会尽可能匹配更多字符。添加?可改为非贪婪模式:
python复制import re
# 贪婪匹配
text = '<div>内容1</div><div>内容2</div>'
print(re.findall(r'<div>.*</div>', text))
# 输出: ['<div>内容1</div><div>内容2</div>']
# 非贪婪匹配
print(re.findall(r'<div>.*?</div>', text))
# 输出: ['<div>内容1</div>', '<div>内容2</div>']
4.3 正则表达式调试
复杂正则表达式可以通过以下方式调试:
- 使用
re.DEBUG标志查看解析过程 - 分步构建正则表达式
- 使用在线正则测试工具验证
python复制import re
pattern = re.compile(r'^\d{3}-\d{4}$', re.DEBUG)
4.4 常见性能问题与优化
-
避免回溯灾难:复杂的嵌套量词可能导致性能问题
- 坏例子:
(a+)* - 好例子:
a+
- 坏例子:
-
使用具体字符集:
[a-z]比.更高效 -
合理使用锚点:
^和$可以提前终止不匹配的尝试 -
避免不必要的捕获组:使用
(?:...)替代(...)表示不捕获
5. 正则表达式实战案例集锦
5.1 日志分析
从服务器日志中提取IP和访问时间:
python复制import re
log = '192.168.1.1 - - [15/Aug/2023:10:12:45 +0800] "GET /index.html HTTP/1.1"'
pattern = r'^(\d+\.\d+\.\d+\.\d+).*\[(.*?)\]'
ip, time = re.search(pattern, log).groups()
print(f'IP: {ip}, 访问时间: {time}')
5.2 数据清洗
清洗不规则的电话号码格式:
python复制import re
def clean_phone(phone):
# 移除非数字字符
cleaned = re.sub(r'[^\d]', '', phone)
# 格式化为标准形式
return re.sub(r'^(\d{3})(\d{4})(\d{4})$', r'\1-\2-\3', cleaned)
print(clean_phone('138 1234 5678')) # 输出: 138-1234-5678
print(clean_phone('(010)12345678')) # 输出: 010-1234-5678
5.3 密码强度验证
验证密码强度(至少8位,包含大小写字母和数字):
python复制import re
def validate_password(password):
if len(password) < 8:
return False
if not re.search(r'[A-Z]', password):
return False
if not re.search(r'[a-z]', password):
return False
if not re.search(r'\d', password):
return False
return True
print(validate_password('Abcd1234')) # True
print(validate_password('abcdefg')) # False
5.4 URL解析
从URL中提取协议、域名和路径:
python复制import re
url = 'https://www.example.com/path/to/page?query=string'
pattern = r'^(https?)://([^/]+)(/.*)?$'
protocol, domain, path = re.match(pattern, url).groups()
print(f'协议: {protocol}') # 输出: https
print(f'域名: {domain}') # 输出: www.example.com
print(f'路径: {path}') # 输出: /path/to/page?query=string
在实际开发中,正则表达式虽然强大,但也不是万能的。对于特别复杂的文本处理需求,可能需要结合其他方法,如字符串方法、专门的解析库等。掌握正则表达式的核心在于理解其匹配原理,并能够根据具体问题设计合适的模式。