基础概念
-
分组和捕获:
- 小括号
()
用于分组。分组不仅可以将多个字符视为一个整体,还可以捕获匹配的子字符串。 - 例如,正则表达式
(abc)
会匹配并捕获字符串"abc"
。
-
捕获组:
- 每一对括号会创建一个捕获组。
- 捕获组会被自动编号,编号从1开始。组0是整个正则表达式的匹配结果。
- 可以使用反向引用引用捕获组,例如
\1
引用第一个捕获组。
捕获组的初级用法——First
捕获组的具体功能
-
捕获和引用:
- 可以在匹配后使用
group(n)
方法获取第 n 个捕获组的内容。例如,re.search(r'(\d+)', '123abc').group(1)
会返回"123"
。 - 捕获组可以在正则表达式中被反向引用。例如,
(\d+)\s\1
匹配两个相同的数字序列,中间有一个空格。
- 可以在匹配后使用
import re
pattern = r'(\d+)-(\d+)-(\d+)'
text = "2024-05-23"
match = re.match(pattern, text)
if match:
print(match.group(0)) # 整个匹配 "2024-05-23"
print(match.group(1)) # 第一个捕获组 "2024"
print(match.group(2)) # 第二个捕获组 "05"
print(match.group(3)) # 第三个捕获组 "23"
-
非捕获组:
- 使用
(?:...)
可以创建非捕获组。这种分组不会捕获匹配的子字符串,不会创建编号的组,但仍然会对模式进行分组。 - 例如,
(?:abc)
匹配"abc"
,但不会捕获它。
- 使用
import re
pattern = r'(?:abc)+'
text = "abcabc"
match = re.match(pattern, text)
if match:
print(match.group(0)) # "abcabc"
-
命名捕获组:
- 使用
(?P<name>...)
可以创建命名捕获组。 - 可以使用名字来引用捕获组,而不是数字。
- 例如,
(?P<word>\w+)
可以通过group('word')
获取匹配的内容。
- 使用
import re
pattern = r'(?P<year>\d+)-(?P<month>\d+)-(?P<day>\d+)'
text = "2024-05-23"
match = re.match(pattern, text)
if match:
print(match.group('year')) # "2024"
print(match.group('month')) # "05"
print(match.group('day')) # "23"
-
后向引用:
- 后向引用指的是在正则表达式中引用之前捕获的组。
- 使用反斜杠加组号
\1
引用第一个捕获组,\2
引用第二个捕获组,以此类推。
import re
pattern = r'(\b\w+\b) \1'
text = "hello hello"
match = re.search(pattern, text)
if match:
print(match.group(0)) # "hello hello"
捕获组的应用场景
-
数据提取:
-
从文本中提取特定格式的数据,例如日期、时间、URL、电子邮件地址等。
-
-
数据验证:
-
验证输入数据的格式是否正确,例如电话号码、邮政编码等。
-
-
文本替换:
- 使用捕获组和反向引用可以在替换操作中重用部分匹配的文本。
-
复杂模式匹配:
-
捕获组可以帮助处理复杂的模式,例如嵌套结构、递归模式等。
-
捕获组的高级用法——Second
-
嵌套捕获组:
- 捕获组可以嵌套使用,组号是按照左括号的出现顺序分配。
import re
pattern = r'((\d{4})-(\d{2})-(\d{2}))'
text = "2024-05-23"
match = re.match(pattern, text)
if match:
print(match.group(0)) # "2024-05-23" (整体匹配)
print(match.group(1)) # "2024-05-23" (第一个捕获组)
print(match.group(2)) # "2024" (第二个捕获组)
print(match.group(3)) # "05" (第三个捕获组)
print(match.group(4)) # "23" (第四个捕获组)
-
后向引用的高级用法:
- 后向引用可以在正则表达式中多次引用捕获组,用于匹配重复的模式
import re
pattern = r'<(\w+)>(.*?)</\1>'
text = "<div>Content</div>"
match = re.match(pattern, text)
if match:
print(match.group(0)) # "<div>Content</div>"
print(match.group(1)) # "div"
print(match.group(2)) # "Content"
-
条件匹配:
-
条件匹配可以基于捕获组是否匹配来决定使用哪种模式。条件匹配的语法是
(?(id/name)yes-pattern|no-pattern)
-
import re
pattern = r'(\d{3})?(\d{3})-(\d{4})(?(1)-(\d{4}))'
text = "123-456-7890"
match = re.match(pattern, text)
if match:
print(match.group(0)) # "123-456-7890"
print(match.group(1)) # None
print(match.group(2)) # "123"
print(match.group(3)) # "456"
print(match.group(4)) # "7890"
-
非贪婪匹配:
-
捕获组默认是贪婪的,尽可能多地匹配字符。可以使用
?
将其转换为非贪婪匹配
-
import re
pattern = r'<(.*?)>'
text = "<div>Content</div>"
match = re.match(pattern, text)
if match:
print(match.group(0)) # "<div>"
print(match.group(1)) # "div"
-
特殊情况处理:
-
转义字符
在捕获组中,某些字符(如
(
,)
,[
,]
,{
,}
,\
,^
,$
,|
,?
,*
,+
,.
)需要转义 -
import re pattern = r'\((\d+)\)' text = "(123)" match = re.match(pattern, text) if match: print(match.group(1)) # "123"
-
忽略大小写
可以使用 '
re.IGNORECASE
' 标志来忽略大小写 -
import re pattern = r'(?i)abc' text = "ABC" match = re.match(pattern, text) if match: print(match.group(0)) # "ABC"
-
多行匹配
可以使用 '
re.MULTILINE
' 标志,使^
和$
匹配每一行的开头和结尾 -
import re pattern = r'^(.*)$' text = "First line\nSecond line" matches = re.findall(pattern, text, re.MULTILINE) print(matches) # ['First line', 'Second line']
-