Python 正则表达式
正则表达式(Regular Expression, 或简称 regex)是一个强大的工具,它使用一种专门的语法来搜索、匹配和操作字符串中的特定模式。Python 通过内置的 re 模块来支持正则表达式。
什么是正则表达式?
想象一下,你想在一个长文本中查找所有电话号码或电子邮件地址。这些模式很难用简单的字符串方法(如 find() 或 startswith())来描述。正则表达式允许你定义一个“模式”,然后用这个模式去匹配你想要的任何复杂字符串。
re 模块的核心函数
re.search(pattern, string)
扫描整个字符串,查找模式第一次出现的位置,如果找到则返回一个匹配对象(Match Object),否则返回 None。
python
import re
text = "The rain in Spain falls mainly in the plain."
# 查找 'ai' 模式
match = re.search(r"ai", text)
if match:
print("Match found!")
print(f"Span: {match.span()}") # 匹配的起止位置: (5, 7)
print(f"String: {match.string}") # 原始字符串
print(f"Group: {match.group()}") # 匹配到的字符串: 'ai'
else:
print("No match found.")
r"..."是什么?r前缀表示这是一个“原始字符串 (raw string)”。在正则表达式中,反斜杠\有特殊含义(如\d表示数字)。使用原始字符串可以防止 Python 解释器对反斜杠进行转义,从而简化正则表达式的书写。
re.findall(pattern, string)
查找字符串中所有与模式匹配的非重叠子串,并以列表形式返回。
python
import re
text = "The rain in Spain falls mainly in the plain."
# 查找所有 'ai' 的实例
all_matches = re.findall(r"ai", text)
print(all_matches) # 输出: ['ai', 'ai', 'ai', 'ai']re.sub(pattern, repl, string)
查找与模式匹配的子串,并用 repl 替换它们。返回替换后的新字符串。
python
import re
text = "My phone number is 123-456-7890."
# 将电话号码替换为 [REDACTED]
redacted_text = re.sub(r"\d{3}-\d{3}-\d{4}", "[REDACTED]", text)
print(redacted_text) # 输出: My phone number is [REDACTED].常用的元字符 (Metacharacters)
元字符是正则表达式中有特殊含义的字符。
| 元字符 | 描述 | 示例 | 匹配 |
|---|---|---|---|
. | 匹配除换行符外的任意单个字符 | a.b | acb, a_b |
^ | 匹配字符串的开头 | ^Hello | Hello World |
$ | 匹配字符串的结尾 | World$ | Hello World |
* | 匹配前一个字符 0 次或多次 | ab*c | ac, abc, abbbc |
+ | 匹配前一个字符 1 次或多次 | ab+c | abc, abbbc (不匹配 ac) |
? | 匹配前一个字符 0 次或 1 次 | ab?c | ac, abc |
{m,n} | 匹配前一个字符 m 到 n 次 | a{2,4} | aa, aaa, aaaa |
[] | 字符集,匹配方括号中的任意一个字符 | [aeiou] | a, e, i, o, u |
\ | 转义特殊字符,或引入特殊序列 | \. | . (字符本身) |
\d | 匹配任意数字 (等同于 [0-9]) | \d+ | 123, 45 |
\D | 匹配任意非数字字符 | ||
\s | 匹配任意空白字符 (空格, tab, 换行) | ||
\S | 匹配任意非空白字符 | ||
\w | 匹配任意字母、数字、下划线 (等同于 [a-zA-Z0-9_]) | ||
\W | 匹配任意非字母、数字、下划线字符 |
分组 (Grouping)
使用圆括号 () 可以对模式进行分组。这有两个主要作用:
- 将多个字符作为一个整体来应用量词(如
*,+,?)。 - 捕获匹配的内容,以便后续引用。
python
import re
text = "Email: john.doe@example.com, User: jane_doe"
# 模式匹配一个完整的电子邮件地址
# (\w+\.\w+) 捕获用户名部分
# (\w+\.\w+) 捕获域名部分
match = re.search(r"(\w+\.\w+)@(\w+\.\w+)", text)
if match:
print(f"Full match: {match.group(0)}") # group(0) 或 group() 是整个匹配
print(f"Username: {match.group(1)}") # group(1) 是第一个括号捕获的内容
print(f"Domain: {match.group(2)}") # group(2) 是第二个括号捕获的内容正则表达式是一个非常广阔和强大的领域,掌握它需要不断的练习。建议使用在线工具(如 regex101.com)来测试和学习模式。