Python正则表达式的常见应用案例
匹配固定格式文本
在处理文本时,经常会遇到需要匹配具有固定格式的内容,比如日期、电话号码、邮箱地址等。
匹配日期格式
日期是一种常见的具有固定格式的数据。常见的日期格式有 YYYY - MM - DD
、MM/DD/YYYY
等。以 YYYY - MM - DD
格式为例,我们可以使用正则表达式来匹配。
import re
date_pattern = re.compile(r'\d{4}-\d{2}-\d{2}')
text = "今天的日期是 2023 - 08 - 15,明天是 2023 - 08 - 16。"
matches = date_pattern.findall(text)
for match in matches:
print(match)
上述代码中,re.compile(r'\d{4}-\d{2}-\d{2}')
定义了一个正则表达式模式。\d
表示任意一个数字字符,{4}
表示前面的字符(这里是数字)出现4次,{2}
表示前面的字符出现2次。所以整个模式表示匹配由4位数字、一个 -
符号、2位数字、一个 -
符号和另外2位数字组成的字符串,即 YYYY - MM - DD
格式的日期。
匹配电话号码
电话号码在不同地区有不同的格式,以常见的中国大陆手机号码为例,其格式为11位数字,且第一位通常为1。
phone_pattern = re.compile(r'1\d{10}')
text = "我的手机号码是13800138000,他的是15900000000。"
matches = phone_pattern.findall(text)
for match in matches:
print(match)
这里 1\d{10}
表示以1开头,后面跟着10个任意数字,这样就可以匹配到中国大陆的手机号码。
匹配邮箱地址
邮箱地址的格式通常为 用户名@域名
。用户名可以包含字母、数字、下划线等,域名部分由多个单词通过 .
连接。
email_pattern = re.compile(r'[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+')
text = "我的邮箱是example@example.com,他的是test_123@test - domain.co.uk。"
matches = email_pattern.findall(text)
for match in matches:
print(match)
在这个正则表达式中,[a-zA-Z0-9_.+-]+
表示用户名部分可以是字母、数字、下划线、点、加号和减号的组合,且至少出现一次。@
是邮箱地址中的固定分隔符。[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+
表示域名部分,其中 [a-zA-Z0-9-]+
表示域名中的单词部分,\.
表示转义后的点号,因为点号在正则表达式中有特殊含义,后面的 [a-zA-Z0-9-.]+
表示顶级域名部分。
文本提取与过滤
正则表达式在从文本中提取有用信息以及过滤掉不需要的内容方面非常有用。
从网页源码中提取链接
当我们需要从网页源码中提取所有的链接时,就可以使用正则表达式。网页链接通常以 http://
或 https://
开头,后面跟着域名和路径等信息。
import requests
import re
url = 'https://example.com'
response = requests.get(url)
html_content = response.text
link_pattern = re.compile(r'https?://[^\s<>"]+|www\.[^\s<>"]+')
links = link_pattern.findall(html_content)
for link in links:
if not link.startswith('http'):
link = 'http://' + link
print(link)
上述代码中,https?://[^\s<>"]+|www\.[^\s<>"]+
这个正则表达式模式可以匹配以 http://
或 https://
开头的链接,以及以 www.
开头的链接。[^\s<>"]+
表示匹配除了空白字符、<
、>
和 "
之外的一个或多个字符。这样就可以从网页源码中提取出链接。
过滤敏感词汇
在文本处理中,有时需要过滤掉一些敏感词汇,比如脏话、公司敏感信息等。
sensitive_words = ['敏感词1', '敏感词2', '敏感词3']
pattern = re.compile('|'.join(sensitive_words))
text = "这是一段包含敏感词1和敏感词2的文本。"
filtered_text = pattern.sub('*' * 5, text)
print(filtered_text)
这里通过 re.compile('|'.join(sensitive_words))
将敏感词列表组合成一个正则表达式模式。|
在正则表达式中表示“或”的关系。然后使用 pattern.sub('*' * 5, text)
将匹配到的敏感词替换为5个 *
号,从而实现敏感词汇的过滤。
字符串替换与格式化
正则表达式在字符串替换和格式化方面也有广泛应用。
替换文本中的特定模式
假设我们有一段文本,其中包含一些旧的格式,需要将其替换为新的格式。比如将文本中的 (数字)
格式替换为 <数字>
。
text = "这里有 (1) 个苹果,(2) 个香蕉。"
pattern = re.compile(r'\((\d+)\)')
new_text = pattern.sub(r'<\1>', text)
print(new_text)
在这个例子中,\((\d+)\)
这个正则表达式模式匹配括号内的数字。(\d+)
是一个捕获组,它捕获一个或多个数字。pattern.sub(r'<\1>', text)
表示将匹配到的内容替换为 <数字>
,其中 \1
表示引用第一个捕获组捕获到的内容,也就是括号内的数字。
格式化文本
有时我们需要将文本按照一定的规则进行格式化。例如,将驼峰命名法的字符串转换为下划线命名法。
import re
def camel_to_snake(camel_str):
pattern = re.compile(r'([a - z])([A - Z])')
return pattern.sub(r'\1_\2', camel_str).lower()
camel_text = "camelCaseText"
snake_text = camel_to_snake(camel_text)
print(snake_text)
这里 ([a - z])([A - Z])
这个正则表达式模式匹配一个小写字母后面跟着一个大写字母的情况。pattern.sub(r'\1_\2', camel_str)
将匹配到的内容替换为小写字母加上下划线再加上大写字母的形式,最后通过 lower()
方法将整个字符串转换为小写,实现了驼峰命名法到下划线命名法的转换。
数据验证
在程序开发中,经常需要对用户输入的数据进行验证,确保其符合特定的格式要求。
验证密码强度
假设我们要求密码必须包含至少8个字符,包括大写字母、小写字母、数字和特殊字符。
import re
def validate_password(password):
pattern = re.compile(r'^(?=.*[a - z])(?=.*[A - Z])(?=.*\d)(?=.*[@$!%*?&])[A - Za - z\d@$!%*?&]{8,}$')
return bool(pattern.fullmatch(password))
password1 = "Abc123@#"
password2 = "abc123"
print(validate_password(password1))
print(validate_password(password2))
在这个正则表达式中,^
表示字符串的开始,$
表示字符串的结束。(?=.*[a - z])
表示字符串中至少包含一个小写字母,(?=.*[A - Z])
表示至少包含一个大写字母,(?=.*\d)
表示至少包含一个数字,(?=.*[@$!%*?&])
表示至少包含一个特殊字符。[A - Za - z\d@$!%*?&]{8,}
表示由字母、数字和特殊字符组成,且长度至少为8。fullmatch
方法用于验证整个字符串是否完全匹配该模式。
验证身份证号码
中国大陆的身份证号码为18位,最后一位可能是数字或 X
。其编码规则较为复杂,但可以通过正则表达式进行基本的格式验证。
import re
def validate_id_number(id_number):
pattern = re.compile(r'^[1 - 9]\d{5}(18|19|20)\d{2}(0[1 - 9]|1[0 - 2])(0[1 - 9]|[12]\d|3[01])\d{3}[\dXx]$')
return bool(pattern.fullmatch(id_number))
id1 = "11010519491001001X"
id2 = "11010519491001001"
print(validate_id_number(id1))
print(validate_id_number(id2))
这里 ^[1 - 9]\d{5}
表示身份证号码的前6位,其中第一位不能为0。(18|19|20)\d{2}
表示年份部分,(0[1 - 9]|1[0 - 2])
表示月份部分,(0[1 - 9]|[12]\d|3[01])
表示日期部分。\d{3}
表示顺序码,[\dXx]$
表示最后一位可以是数字或 X
(不区分大小写)。通过 fullmatch
方法验证整个身份证号码是否符合该格式。
处理日志文件
日志文件是记录程序运行过程中各种信息的文件,通过正则表达式可以方便地从日志文件中提取关键信息。
提取日志中的时间戳
很多日志文件都会在每条记录中包含时间戳,以便记录事件发生的时间。假设日志格式为 [时间戳] [日志级别] [消息]
,我们可以提取其中的时间戳。
import re
log_text = "[2023 - 08 - 15 10:30:00] INFO Program started."
pattern = re.compile(r'\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\]')
match = pattern.search(log_text)
if match:
print(match.group(1))
在这个例子中,\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\]
这个正则表达式模式用于匹配方括号内的时间戳格式。(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})
是一个捕获组,用于捕获具体的时间戳内容。search
方法在日志文本中查找匹配的内容,如果找到则通过 group(1)
提取捕获组中的内容,即时间戳。
统计特定类型的日志数量
假设我们要统计日志文件中 ERROR
级别的日志数量。
import re
log_text = """
[2023 - 08 - 15 10:30:00] INFO Program started.
[2023 - 08 - 15 10:35:00] ERROR Something went wrong.
[2023 - 08 - 15 10:40:00] INFO Another info.
[2023 - 08 - 15 10:45:00] ERROR Another error.
"""
pattern = re.compile(r'\[.*\] ERROR ')
error_count = len(pattern.findall(log_text))
print(f"ERROR 级别的日志数量: {error_count}")
这里 \[.*\] ERROR
这个正则表达式模式用于匹配以 [
开始,后面跟着任意字符,再接着是 ERROR
的内容。通过 findall
方法找到所有匹配的内容,然后通过 len
函数统计数量,从而得到 ERROR
级别的日志数量。
解析配置文件
配置文件通常包含各种配置项和对应的值,正则表达式可以帮助我们解析这些配置文件。
解析简单的键值对配置文件
假设配置文件的格式为 键 = 值
,每行一个键值对。
import re
config_text = """
name = John
age = 30
city = New York
"""
pattern = re.compile(r'(\w+) = (\S+)')
matches = pattern.findall(config_text)
config_dict = {match[0]: match[1] for match in matches}
print(config_dict)
在这个例子中,(\w+) = (\S+)
这个正则表达式模式用于匹配键值对。(\w+)
是一个捕获组,用于捕获键(单词字符组成),=
是固定的分隔符,(\S+)
是另一个捕获组,用于捕获值(非空白字符组成)。通过 findall
方法找到所有的键值对,然后使用字典推导式将其转换为字典。
解析INI格式的配置文件
INI 格式的配置文件通常包含节(section),每个节下有多个键值对。例如:
[database]
host = 127.0.0.1
port = 3306
user = root
password = password123
[server]
address = 0.0.0.0
port = 8080
import re
ini_text = """
[database]
host = 127.0.0.1
port = 3306
user = root
password = password123
[server]
address = 0.0.0.0
port = 8080
"""
section_pattern = re.compile(r'\[(\w+)\]')
key_value_pattern = re.compile(r'(\w+) = (\S+)')
config = {}
sections = section_pattern.split(ini_text)
for i in range(1, len(sections), 2):
section = sections[i]
config[section] = {}
key_value_text = sections[i + 1]
key_value_matches = key_value_pattern.findall(key_value_text)
for key, value in key_value_matches:
config[section][key] = value
print(config)
这里首先使用 \[(\w+)\]
这个正则表达式模式来匹配节的名称,通过 split
方法将配置文件按节分割。然后对于每个节,使用 (\w+) = (\S+)
这个模式来匹配节内的键值对,将其存储到字典中,最终得到一个嵌套字典形式的配置数据。
通过以上这些常见应用案例,可以看出正则表达式在 Python 文本处理中发挥着重要作用,无论是数据验证、文本提取、替换还是配置文件解析等方面,都能借助正则表达式高效地完成任务。在实际应用中,需要根据具体的需求和文本特点,灵活构造合适的正则表达式模式。