在 Python 编程的广阔天地里,正则表达式宛如一把万能钥匙,开启了高效文本处理的大门。无论是从海量文本中精准提取关键信息,还是对输入数据进行严格的格式验证,正则表达式都展现出了无可比拟的强大功能。它通过定义特定的模式,让程序能够灵活地匹配、搜索、替换文本内容。接下来,让我们深入探索 Python 正则表达式的语法规则、常用函数以及丰富的应用场景。
语法规则:构建匹配模式的基石
普通字符与元字符
正则表达式由普通字符和具有特殊含义的元字符组成。普通字符,如其字面所示,代表匹配该字符本身。例如,模式'a'将匹配字符串中出现的字符'a'。
而元字符则是正则表达式的灵魂所在,它们赋予了表达式强大的匹配能力。常见的元字符包括:
- .:匹配除换行符\n外的任意单个字符。比如模式'c.t',它可以匹配'cat'、'cut'、'c t'等字符串,只要中间字符存在且不是换行符即可。
- ^:匹配字符串的开头位置。模式'^hello'只会在字符串以'hello'开头时才会匹配成功,如'hello world',而'world hello'则无法匹配。
- $:匹配字符串的结尾位置。'worl$'仅在字符串以'world'结尾时匹配,例如'hello world',而'world hello'则不匹配。
- :表示其前面的字符或字符组可以出现零次或多次。例如,'ab'可以匹配'a'(此时'b'出现 0 次)、'ab'、'abb'、'abbb'等字符串。
- +:意味着其前面的字符或字符组至少出现一次。所以'ab+'能匹配'ab'、'abb'、'abbb'等,但不能匹配'a'。
- ?:表示其前面的字符或字符组可以出现零次或一次。'ab?'可匹配'a'或'ab'。
- {n}:指定其前面的字符或字符组恰好出现n次。如'a{3}'只匹配'aaa'。
- {n,m}:表示其前面的字符或字符组至少出现n次,最多出现m次。例如'a{2,4}',可以匹配'aa'、'aaa'、'aaaa'。
字符类
字符类用方括号[]表示,用于匹配方括号内的任意一个字符。比如'[abc]',它可以匹配'a'、'b'或'c'中的任意一个字符。也可以使用范围表示,如'[a - z]'匹配任意小写字母,'[0 - 9]'匹配任意数字。通过在方括号内加上^,可以实现取反匹配,'[^0 - 9]'表示匹配除数字以外的任意字符。
转义字符
转义字符\用于取消元字符的特殊含义,使其作为普通字符进行匹配。当我们想要匹配像'.'、'*'、'['等本身具有特殊意义的字符时,就需要使用转义字符。例如,'\.'匹配字符'.','\*'匹配字符'*'。
分组和捕获
使用圆括号()可以将表达式分组,并对分组后的内容进行操作。例如,'(ab)+'表示匹配由连续的'ab'组成的字符串,如'ab'、'abab'、'ababab'等。通过分组,还可以在后续操作中引用分组匹配到的内容,这在一些复杂的文本处理场景中非常有用。此外,(?:)这种形式表示只分组不捕获,不会创建捕获组,在一些仅需对部分模式进行整体操作但又不想增加捕获组开销的情况下使用。
常用函数:正则表达式操作的利器
Python 通过内置的re模块来支持正则表达式操作。以下是re模块中一些常用的函数:
re.match(pattern, string)
re.match函数尝试从字符串的开头开始匹配正则表达式pattern。如果匹配成功,返回一个匹配对象;否则返回None。例如:
import re
match = re.match(r'hello', 'hello world')
if match:
print("匹配成功")
else:
print("匹配失败")
在这个例子中,由于字符串'hello world'是以'hello'开头的,所以re.match函数匹配成功。
re.search(pattern, string)
re.search函数在整个字符串中搜索正则表达式pattern的第一个匹配项。一旦找到匹配项,就返回一个匹配对象;若未找到,则返回None。与re.match不同,re.search不要求从字符串开头开始匹配。例如:
import re
match = re.search(r'world', 'hello world')
if match:
print("找到匹配项")
else:
print("未找到匹配项")
这里,尽管'world'不在字符串开头,但re.search依然能找到匹配项。
re.findall(pattern, string)
re.findall函数会在字符串中搜索所有与正则表达式pattern匹配的项,并以列表的形式返回所有匹配到的字符串。比如,要从一个字符串中提取所有数字:
import re
text = "这里有数字123,还有456和789"
numbers = re.findall(r'\d+', text)
print(numbers)
输出结果为['123', '456', '789'],其中'\d+'表示匹配一个或多个数字。
re.finditer(pattern, string)
re.finditer函数与re.findall类似,也是在字符串中搜索所有匹配项。不过,它返回的是一个迭代器,迭代器中的每个元素都是一个匹配对象。通过这种方式,可以在处理大量匹配结果时,避免一次性将所有结果存储在内存中,提高效率。例如:
import re
text = "这里有数字123,还有456和789"
for match in re.finditer(r'\d+', text):
print(match.group())
输出结果同样为123、456、789,但这里是通过迭代匹配对象来获取每个匹配的数字。
re.sub(pattern, repl, string)
re.sub函数用于在字符串中搜索正则表达式pattern,并将所有匹配的部分替换为指定的字符串repl。例如,将字符串中的所有数字替换为'X':
import re
text = "这里有数字123,还有456和789"
new_text = re.sub(r'\d+', 'X', text)
print(new_text)
输出结果为"这里有数字X,还有X和X"。
应用场景:正则表达式的用武之地
数据提取
在文本处理中,经常需要从大量文本中提取特定格式的数据。例如,从一篇新闻报道中提取所有的邮箱地址。假设新闻内容存储在字符串news_text中:
import re
news_text = "联系我们请发邮件至info@example.com,或联系support@example.net获取更多帮助。"
emails = re.findall(r'\b[A - Za - z0 - 9._%+-]+@[A - Za - z0 - 9.-]+\.[A - Za - z]{2,}\b', news_text)
print(emails)
上述代码中的正则表达式能够匹配常见的邮箱地址格式,运行结果将返回['info@example.com','support@example.net']。
数据验证
在用户输入数据时,需要对数据格式进行验证,确保其符合特定要求。比如,验证用户输入的手机号码是否合法。假设手机号码格式为 11 位数字,且以 1 开头:
import re
phone_number = "13800138000"
pattern = r'^1\d{10}