正则表达式是一种强大的文本处理工具,它能帮助我们快速检查、查找和替换文本内容。在Python中,我们使用re模块来处理正则表达式。
正则表达式就像是文本的"搜索模式"。比如你想在一篇文章中找出所有的电子邮箱,或者验证用户输入的手机号格式是否正确,正则表达式都能帮上忙。
re.match()只检查字符串的开头是否符合模式。
import re
# 检查字符串是否以"Hello"开头
result = re.match(r'Hello', 'Hello world!')
if result:
print("匹配成功:", result.group())
else:
print("匹配失败")
# 输出:匹配成功: Hello
# 这个会失败,因为不是从开头匹配
result2 = re.match(r'world', 'Hello world!')
print(result2) # 输出:Nonere.search()会在整个字符串中搜索第一个匹配的位置。
import re
# 在字符串中搜索数字
text = "我的电话是13800138000"
result = re.search(r'\d+', text)
if result:
print("找到数字:", result.group()) # 输出:找到数字: 13800138000
# 搜索邮箱地址
text = "联系邮箱:test@fly63.com"
result = re.search(r'\w+@\w+\.\w+', text)
if result:
print("找到邮箱:", result.group()) # 输出:找到邮箱:test@fly63.comimport re
text = "Python编程学习"
# match只在开头匹配
match_result = re.match(r'编程', text)
print("match结果:", match_result) # None
# search在整个字符串搜索
search_result = re.search(r'编程', text)
print("search结果:", search_result.group()) # 编程import re
# 从文本中提取所有数字
text = "今天气温25度,明天气温28度,后天气温26度"
numbers = re.findall(r'\d+', text)
print("所有温度:", numbers) # 输出:['25', '28', '26']
# 提取日期
text = "会议时间:2024-01-15,地点:北京"
date = re.search(r'\d{4}-\d{2}-\d{2}', text)
if date:
print("会议日期:", date.group()) # 输出:会议日期: 2024-01-15import re
def validate_phone(phone):
"""验证手机号格式"""
pattern = r'^1[3-9]\d{9}$'
if re.match(pattern, phone):
return True
return False
def validate_email(email):
"""验证邮箱格式"""
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
if re.match(pattern, email):
return True
return False
# 测试
print("手机号验证:")
print("13800138000:", validate_phone("13800138000")) # True
print("12345678901:", validate_phone("12345678901")) # False
print("\n邮箱验证:")
print("test@fly63.com:", validate_email("test@fly63.com")) # True
print("invalid-email:", validate_email("invalid-email")) # Falseimport re
# 隐藏手机号中间四位
phone = "用户手机:13800138000"
hidden_phone = re.sub(r'(\d{3})\d{4}(\d{4})', r'\1****\2', phone)
print(hidden_phone) # 输出:用户手机:138****8000
# 清理文本中的html标签
html_text = "<p>这是一个<strong>测试</strong>文本</p>"
clean_text = re.sub(r'<[^>]+>', '', html_text)
print(clean_text) # 输出:这是一个测试文本
# 统一日期格式
dates = "2024/01/15 和 2024-01-20"
uniform_dates = re.sub(r'(\d{4})/(\d{2})/(\d{2})', r'\1-\2-\3', dates)
print(uniform_dates) # 输出:2024-01-15 和 2024-01-20import re
def convert_to_uppercase(match):
"""将匹配的文本转为大写"""
return match.group().upper()
text = "hello world, python programming"
result = re.sub(r'\b\w+\b', convert_to_uppercase, text)
print(result) # 输出:HELLO WORLD, PYTHON PROGRAMMING分组让我们能提取匹配的特定部分。
import re
# 提取姓名和年龄
text = "姓名:张三,年龄:25;姓名:李四,年龄:30"
pattern = r'姓名:(\w+),年龄:(\d+)'
matches = re.findall(pattern, text)
for name, age in matches:
print(f"姓名:{name}, 年龄:{age}")
# 输出:
# 姓名:张三, 年龄:25
# 姓名:李四, 年龄:30
# 使用search提取分组
text = "出生日期:1990-05-15"
match = re.search(r'(\d{4})-(\d{2})-(\d{2})', text)
if match:
year, month, day = match.groups()
print(f"年:{year}, 月:{month}, 日:{day}") # 输出:年:1990, 月:05, 日:15如果需要多次使用同一个模式,可以先编译它,这样效率更高。
import re
# 编译正则表达式
phone_pattern = re.compile(r'1[3-9]\d{9}')
email_pattern = re.compile(r'\w+@\w+\.\w+')
# 重复使用编译后的模式
texts = [
"电话13800138000,邮箱test@fly63.com",
"联系13912345678,邮箱admin@fly63.com"
]
for text in texts:
phone = phone_pattern.search(text)
email = email_pattern.search(text)
if phone:
print("找到手机:", phone.group())
if email:
print("找到邮箱:", email.group())import re
text = "Python3.9 发布啦!价格是$199.99"
# 匹配数字
numbers = re.findall(r'\d+', text)
print("数字:", numbers) # ['3', '9', '199', '99']
# 匹配单词
words = re.findall(r'[a-zA-Z]+', text)
print("单词:", words) # ['Python', '发布啦', '价格是']
# 匹配价格
price = re.search(r'\$\d+\.\d{2}', text)
if price:
print("价格:", price.group()) # $199.99import re
class PatternValidator:
"""常用正则表达式验证器"""
@staticmethod
def is_chinese(text):
"""检查是否为中文"""
return bool(re.match(r'^[\u4e00-\u9fa5]+$', text))
@staticmethod
def is_id_card(id_card):
"""检查身份证格式(简单版本)"""
return bool(re.match(r'^\d{17}[\dXx]$', id_card))
@staticmethod
def is_username(username):
"""检查用户名(4-16位字母数字下划线)"""
return bool(re.match(r'^[a-zA-Z0-9_]{4,16}$', username))
@staticmethod
def extract_urls(text):
"""提取URL"""
return re.findall(r'https?://[^\s]+', text)
# 使用示例
validator = PatternValidator()
print("中文验证:", validator.is_chinese("中文测试")) # True
print("用户名验证:", validator.is_username("user_123")) # True
text = "访问https://fly63.com和http://example.com"
print("提取URL:", validator.extract_urls(text)) # ['https://fly63.com', 'http://example.com']import re
from collections import Counter
def analyze_log_file(file_path):
"""分析日志文件中的IP地址"""
ip_counter = Counter()
# IP地址模式
ip_pattern = re.compile(r'\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b')
try:
with open(file_path, 'r', encoding='utf-8') as file:
for line in file:
ips = ip_pattern.findall(line)
ip_counter.update(ips)
print("访问统计:")
for ip, count in ip_counter.most_common(10):
print(f" {ip}: {count}次")
except FileNotFoundError:
print("文件不存在")
# 使用示例
# analyze_log_file("access.log")import re
def extract_comments(code):
"""提取Python代码中的注释"""
# 匹配单行注释
single_line_comments = re.findall(r'#.*$', code, re.MULTILINE)
# 匹配多行注释
multi_line_comments = re.findall(r"'''.*?'''", code, re.DOTALL)
multi_line_comments.extend(re.findall(r'""".*?"""', code, re.DOTALL))
return single_line_comments, multi_line_comments
# 示例代码
sample_code = '''
def calculate_sum(a, b):
# 这是一个加法函数
"""计算两个数的和"""
return a + b # 返回结果
# 主程序
if __name__ == "__main__":
result = calculate_sum(5, 3)
'''
single, multi = extract_comments(sample_code)
print("单行注释:", single)
print("多行注释:", multi)import re
text = "<div>内容1</div><div>内容2</div>"
# 贪婪匹配(默认)
greedy = re.findall(r'<div>.*</div>', text)
print("贪婪匹配:", greedy) # ['<div>内容1</div><div>内容2</div>']
# 非贪婪匹配
non_greedy = re.findall(r'<div>.*?</div>', text)
print("非贪婪匹配:", non_greedy) # ['<div>内容1</div>', '<div>内容2</div>']import re
text = "苹果价格:¥20, 香蕉价格:¥15, 橙子价格:¥25"
# 查找价格数字(在¥之后)
prices = re.findall(r'¥(\d+)', text)
print("价格:", prices) # ['20', '15', '25']
# 查找商品名(在价格之前)
products = re.findall(r'(\w+)(?=价格)', text)
print("商品:", products) # ['苹果', '香蕉', '橙子']import re
def escape_special_chars(text):
"""转义正则表达式特殊字符"""
special_chars = r'\.^$*+?{}[]|()'
for char in special_chars:
text = text.replace(char, '\\' + char)
return text
# 搜索包含特殊字符的文本
search_text = "价格是$20.99 (特价)"
escaped_text = escape_special_chars(search_text)
pattern = re.compile(escaped_text)
text = "当前价格是$20.99 (特价),很划算"
match = pattern.search(text)
if match:
print("找到:", match.group()) # 价格是$20.99 (特价)import re
import time
def measure_performance():
"""比较编译和未编译的性能"""
text = "测试文本" * 1000
# 未编译
start = time.time()
for i in range(1000):
re.search(r'测试', text)
uncompiled_time = time.time() - start
# 编译后
pattern = re.compile(r'测试')
start = time.time()
for i in range(1000):
pattern.search(text)
compiled_time = time.time() - start
print(f"未编译: {uncompiled_time:.4f}秒")
print(f"编译后: {compiled_time:.4f}秒")
print(f"性能提升: {uncompiled_time/compiled_time:.1f}倍")
measure_performance()import re
def test_regex(pattern, test_cases):
"""测试正则表达式"""
compiled = re.compile(pattern)
print(f"测试模式: {pattern}")
print("-" * 40)
for test_case in test_cases:
match = compiled.search(test_case)
result = "匹配" if match else "不匹配"
print(f"'{test_case}' -> {result}")
if match:
print(f" 匹配内容: {match.group()}")
# 测试邮箱验证
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
test_cases = [
"test@fly63.com",
"invalid-email",
"user.name@domain.co.uk",
"missing@dot"
]
test_regex(email_pattern, test_cases)掌握正则表达式需要练习,建议从简单的模式开始,逐步尝试更复杂的匹配。在实际项目中,正则表达式能大大简化文本处理工作。
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。
以下标志可以单独使用,也可以通过按位或(|)组合使用。例如,re.IGNORECASE | re.MULTILINE 表示同时启用忽略大小写和多行模式。
| 修饰符 | 描述 | 实例 |
|---|---|---|
| re.IGNORECASE 或 re.I | 使匹配对大小写不敏感 | |
| re.MULTILINE 或 re.M | 多行匹配,影响 ^ 和 $,使它们匹配字符串的每一行的开头和结尾。 | |
| re.DOTALL 或 re.S: | 使 . 匹配包括换行符在内的任意字符。 | |
| re.ASCII | 使 \w, \W, \b, \B, \d, \D, \s, \S 仅匹配 ASCII 字符。 | |
| re.VERBOSE 或 re.X | 忽略空格和注释,可以更清晰地组织复杂的正则表达式。 | |
模式字符串使用特殊的语法来表示一个正则表达式。
字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。
多数字母和数字前加一个反斜杠时会拥有不同的含义。
标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
反斜杠本身需要使用反斜杠转义。
由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r'\t',等价于 \\t )匹配相应的特殊字符。
下表列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。
| 模式 | 描述 |
|---|---|
| ^ | 匹配字符串的开头 |
| $ | 匹配字符串的末尾。 |
| . | 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。 |
| [...] | 用来匹配所包含的任意一个字符,例如 [amk] 匹配 'a','m'或'k' |
| [^...] | 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。 |
| re* | 匹配0个或多个的表达式。 |
| re+ | 匹配1个或多个的表达式。 |
| re? | 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式 |
| re{ n} | 匹配n个前面表达式。例如,"o{2}"不能匹配"Bob"中的"o",但是能匹配"food"中的两个o。 |
| re{ n,} | 精确匹配n个前面表达式。例如,"o{2,}"不能匹配"Bob"中的"o",但能匹配"foooood"中的所有o。"o{1,}"等价于"o+"。"o{0,}"则等价于"o*"。 |
| re{ n, m} | 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式 |
| a| b | 匹配a或b |
| (re) | 匹配括号内的表达式,也表示一个组 |
| (?imx) | 正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。 |
| (?-imx) | 正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。 |
| (?: re) | 类似 (...), 但是不表示一个组 |
| (?imx: re) | 在括号中使用i, m, 或 x 可选标志 |
| (?-imx: re) | 在括号中不使用i, m, 或 x 可选标志 |
| (?#...) | 注释. |
| (?= re) | 前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。 |
| (?! re) | 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功。 |
| (?> re) | 匹配的独立模式,省去回溯。 |
| \w | 匹配数字字母下划线 |
| \W | 匹配非数字字母下划线 |
| \s | 匹配任意空白字符,等价于 [\t\n\r\f]。 |
| \S | 匹配任意非空字符 |
| \d | 匹配任意数字,等价于 [0-9]。 |
| \D | 匹配任意非数字 |
| \A | 匹配字符串开始 |
| \Z | 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。 |
| \z | 匹配字符串结束 |
| \G | 匹配最后匹配完成的位置。 |
| \b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。 |
| \B | 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'。 |
| \n, \t, 等。 | 匹配一个换行符。匹配一个制表符, 等 |
| \1...\9 | 匹配第n个分组的内容。 |
| \10 | 匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。 |
| 实例 | 描述 |
|---|---|
| python | 匹配 "python". |
| 实例 | 描述 |
|---|---|
| [Pp]ython | 匹配 "Python" 或 "python" |
| rub[ye] | 匹配 "ruby" 或 "rube" |
| [aeiou] | 匹配中括号内的任意一个字母 |
| [0-9] | 匹配任何数字。类似于 [0123456789] |
| [a-z] | 匹配任何小写字母 |
| [A-Z] | 匹配任何大写字母 |
| [a-zA-Z0-9] | 匹配任何字母及数字 |
| [^aeiou] | 除了aeiou字母以外的所有字符 |
| [^0-9] | 匹配除了数字外的字符 |
| 实例 | 描述 |
|---|---|
| . | 匹配除 "\n" 之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用象 '[.\n]' 的模式。 |
| \d | 匹配一个数字字符。等价于 [0-9]。 |
| \D | 匹配一个非数字字符。等价于 [^0-9]。 |
| \s | 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。 |
| \S | 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。 |
| \w | 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。 |
| \W | 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。 |
本文内容仅供个人学习/研究/参考使用,不构成任何决策建议或专业指导。分享/转载时请标明原文来源,同时请勿将内容用于商业售卖、虚假宣传等非学习用途哦~感谢您的理解与支持!