re
模块是Python中用于正则表达式操作的标准库模块。正则表达式(Regular Expression)是一种强大的文本处理工具,可以用来匹配、查找、替换字符串中的特定模式。
1. re模块的基本方法
1.1 re.compile()
将正则表达式模式编译成一个正则表达式对象,可以重复使用。
python
import re
pattern = re.compile(r'\d+') # 匹配一个或多个数字
1.2 re.match()
从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功则返回None。
python
result = re.match(r'hello', 'hello world')
if result:
print("匹配成功:", result.group()) # 输出: 匹配成功: hello
1.3 re.search()
扫描整个字符串并返回第一个成功的匹配。
python
result = re.search(r'world', 'hello world')
if result:
print("找到匹配:", result.group()) # 输出: 找到匹配: world
1.4 re.findall()
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表。
python
numbers = re.findall(r'\d+', '12 apples, 34 oranges, 56 bananas')
print(numbers) # 输出: ['12', '34', '56']
1.5 re.finditer()
与findall类似,但返回一个迭代器,包含所有匹配的Match对象。
python
matches = re.finditer(r'\d+', '12 apples, 34 oranges, 56 bananas')
for match in matches:
print(match.group(), match.span())
1.6 re.sub()
用于替换字符串中的匹配项。
python
text = re.sub(r'\d+', 'NUM', '12 apples, 34 oranges, 56 bananas')
print(text) # 输出: NUM apples, NUM oranges, NUM bananas
1.7 re.split()
按照能够匹配的子串将字符串分割后返回列表。
python
words = re.split(r'\W+', 'Hello, world! This is a test.')
print(words) # 输出: ['Hello', 'world', 'This', 'is', 'a', 'test', '']
2. 正则表达式对象的方法
编译后的正则表达式对象也有相应的方法:
python
pattern = re.compile(r'\d+')
# 对应的方法
pattern.match(string) # 同re.match()
pattern.search(string) # 同re.search()
pattern.findall(string) # 同re.findall()
pattern.finditer(string) # 同re.finditer()
pattern.sub(repl, string) # 同re.sub()
pattern.split(string) # 同re.split()
3. Match对象的方法和属性
匹配成功后返回的Match对象有以下常用方法和属性:
3.1 方法
group([group1, ...])
: 返回一个或多个匹配的子组groups()
: 返回一个包含所有匹配子组的元组groupdict()
: 返回一个包含所有命名子组的字典start([group])
: 返回匹配子组的起始位置end([group])
: 返回匹配子组的结束位置span([group])
: 返回一个元组包含匹配子组的(start, end)位置
3.2 属性
pos
: 搜索开始的位置endpos
: 搜索结束的位置lastindex
: 最后一个匹配的捕获组的索引lastgroup
: 最后一个匹配的捕获组的名称re
: 产生此匹配的正则表达式对象string
: 匹配的字符串
4. 正则表达式模式语法
4.1 常用元字符
.
: 匹配任意字符(除了换行符)^
: 匹配字符串的开头$
: 匹配字符串的结尾*
: 匹配前面的子表达式零次或多次+
: 匹配前面的子表达式一次或多次?
: 匹配前面的子表达式零次或一次{m}
: 匹配前面的子表达式m次{m,n}
: 匹配前面的子表达式m到n次[...]
: 字符集,匹配其中任意一个字符|
: 或,匹配|左右任意一个表达式(...)
: 分组,标记一个子表达式的开始和结束位置
4.2 特殊序列
\d
: 匹配任意数字,等价于[0-9]\D
: 匹配任意非数字字符\s
: 匹配任意空白字符\S
: 匹配任意非空白字符\w
: 匹配任意字母数字字符,等价于[a-zA-Z0-9_]\W
: 匹配任意非字母数字字符\b
: 匹配单词边界\B
: 匹配非单词边界
5. 高级用法
5.1 分组和捕获
python
pattern = re.compile(r'(\d{3})-(\d{3})-(\d{4})') # 电话号码格式
match = pattern.search('我的电话是123-456-7890')
if match:
print("完整匹配:", match.group(0)) # 123-456-7890
print("区号:", match.group(1)) # 123
print("前三位:", match.group(2)) # 456
print("后四位:", match.group(3)) # 7890
print("所有分组:", match.groups()) # ('123', '456', '7890')
5.2 非捕获组
(?:...)
表示非捕获组,匹配但不捕获
python
pattern = re.compile(r'(?:\d{3})-(\d{3})-(\d{4})')
match = pattern.search('123-456-7890')
print(match.groups()) # 输出: ('456', '7890')
5.3 命名组
(?P<name>...)
可以给分组命名
python
pattern = re.compile(r'(?P<area>\d{3})-(?P<first>\d{3})-(?P<last>\d{4})')
match = pattern.search('123-456-7890')
print(match.groupdict()) # {'area': '123', 'first': '456', 'last': '7890'}
5.4 前后查找
(?=...)
: 正向后查找(?!...)
: 负向后查找(?<=...)
: 正向前查找(?<!...)
: 负向前查找
python
# 匹配后面跟着"bar"的"foo"
re.findall(r'foo(?=bar)', 'foobar foobaz') # ['foo']
# 匹配后面不跟着"bar"的"foo"
re.findall(r'foo(?!bar)', 'foobar foobaz') # ['foo']
# 匹配前面是"foo"的"bar"
re.findall(r'(?<=foo)bar', 'foobar bazbar') # ['bar']
# 匹配前面不是"foo"的"bar"
re.findall(r'(?<!foo)bar', 'foobar bazbar') # ['bar']
6. 标志参数
re模块支持多个标志参数,可以修改正则表达式的行为:
re.IGNORECASE
或re.I
: 忽略大小写re.MULTILINE
或re.M
: 多行模式re.DOTALL
或re.S
: 使.匹配包括换行符在内的所有字符re.VERBOSE
或re.X
: 允许编写更易读的正则表达式re.ASCII
或re.A
: 使\w, \W, \b, \B, \s, \S只匹配ASCII字符re.DEBUG
: 显示调试信息
python
# 忽略大小写
re.findall(r'hello', 'Hello World', re.I) # ['Hello']
# 多行模式
text = """first line
second line
third line"""
re.findall(r'^\w+', text, re.M) # ['first', 'second', 'third']
# 详细模式,可以添加注释和空白
pattern = re.compile(r"""
\d{3} # 区号
- # 分隔符
\d{3} # 前三位
- # 分隔符
\d{4} # 后四位
""", re.VERBOSE)
7. 实际应用示例
7.1 验证电子邮件地址
python
def is_valid_email(email):
pattern = re.compile(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$')
return bool(pattern.match(email))
print(is_valid_email('user@example.com')) # True
print(is_valid_email('invalid.email@')) # False
7.2 提取URL
python
text = "访问我的网站 https://www.example.com 或者 http://test.org"
urls = re.findall(r'https?://[^\s]+', text)
print(urls) # ['https://www.example.com', 'http://test.org']
7.3 替换日期格式
python
text = "今天是2023-05-15,明天是2023-05-16"
new_text = re.sub(r'(\d{4})-(\d{2})-(\d{2})', r'\2/\3/\1', text)
print(new_text) # 今天是05/15/2023,明天是05/16/2023
7.4 密码强度验证
python
def check_password_strength(password):
if len(password) < 8:
return "密码太短"
if not re.search(r'[A-Z]', password):
return "需要至少一个大写字母"
if not re.search(r'[a-z]', password):
return "需要至少一个小写字母"
if not re.search(r'\d', password):
return "需要至少一个数字"
if not re.search(r'[^A-Za-z0-9]', password):
return "需要至少一个特殊字符"
return "密码强度足够"
print(check_password_strength('Weak123')) # 密码太短
print(check_password_strength('Strong@Password123')) # 密码强度足够
8. 性能考虑
- 预编译正则表达式 :如果需要多次使用同一个正则表达式,使用
re.compile()
预编译可以提高性能。 - 避免贪婪匹配 :贪婪匹配(如
.*
)可能会导致性能问题,尽量使用非贪婪匹配(如.*?
)或更具体的模式。 - 使用原子组 :
(?>...)
可以防止回溯,提高性能。 - 避免过度使用捕获组 :只捕获需要的内容,使用非捕获组
(?:...)
减少开销。
python
# 预编译示例
pattern = re.compile(r'\d+') # 编译一次
for text in large_text_collection:
matches = pattern.findall(text) # 多次使用
正则表达式是一个强大的工具,但也可能变得复杂难以维护。对于特别复杂的模式,考虑将其分解为多个简单的正则表达式,或者编写专门的解析器。