python爬虫 - 深入正则表达式

  🌈个人主页:https://blog.csdn.net/2401_86688088?type=blog
🔥 系列专栏:https://blog.csdn.net/2401_86688088/category_12797772.html

目录

前言

一、匹配多个字符

(一)匹配任意多个字符

(二)匹配一个或多个字符

(三)匹配特定数量的字符

(四)匹配字符范围

(五)匹配非数字、非字母等

(六)使用 re.DOTALL 匹配多行

(七)匹配指定开头或结尾的多个字符

(八)匹配字母、数字、空白符

(九)匹配多个字符总结

二、匹配开头和结尾

(一)匹配字符串的开头:^

(二)匹配字符串的结尾:$

(三)同时匹配开头和结尾

(四)匹配多行模式

(五)示例:验证电子邮件

(六)匹配开头和结尾总结

三、匹配分组

(一)基本分组

(二)命名分组

(三)非捕获分组

(四)使用 groups() 提取所有分组

(五)反向引用分组

(六)分组嵌套

(七)忽略大小写和多行分组匹配

(八)匹配分组总结

四、总结


前言

正则表达式是一种灵活且强大的工具,用于匹配和操作文本。它广泛应用于编程、文本处理、数据清理和验证等领域。在 Python 中,通过内置的 re 模块,开发者可以轻松使用正则表达式来解决复杂的文本匹配问题。本篇文章详细介绍了正则表达式中的多字符匹配、开头和结尾匹配、分组匹配等重要概念及其应用。通过这些示例与技巧,读者将能够掌握如何在 Python 中运用正则表达式处理多种场景下的文本操作需求。


一、匹配多个字符

在正则表达式中,匹配多个字符的方式取决于你要匹配的字符类型和数量。正则表达式通过量词和字符集的组合,能够灵活地匹配任意长度的字符串。以下是一些常见的正则匹配多个字符的方式:

(一)匹配任意多个字符

使用 .* 匹配任意多个字符(包括0个),其中 . 表示任意单个字符,* 表示前面的字符出现0次或多次。

示例:

import re
text = "hello world"
result = re.findall(r'.*', text)
print(result)  # 输出: ['hello world', '']

(二)匹配一个或多个字符

使用 + 匹配前面的字符一次或多次,保证至少匹配一个字符。

示例:

import re
text = "abc123"
result = re.findall(r'\d+', text)
print(result)  # 输出: ['123']

(三)匹配特定数量的字符

  • 使用 {n} 来精确匹配前面的字符 n 次。

  • 使用 {n,m} 来匹配前面的字符至少 n 次,至多 m 次。

示例:

import re
text = "12345"
# 匹配恰好5个数字
result = re.findall(r'\d{5}', text)
print(result)  # 输出: ['12345']

(四)匹配字符范围

使用字符集 [] 匹配多个特定字符,或者使用字符范围(如 [a-z])来匹配多个连续字符。

示例:

import re
text = "abcdef123"
result = re.findall(r'[a-f]+', text)  # 匹配a-f范围内的多个字符
print(result)  # 输出: ['abcdef']

(五)匹配非数字、非字母等

使用反向匹配 [^] 来匹配多个不属于某类的字符。例如,[^0-9]+ 匹配非数字的字符序列。

示例:

import re
text = "abc123def"
# 匹配非数字的字符序列
result = re.findall(r'[^0-9]+', text)
print(result)  # 输出: ['abc', 'def']

(六)使用 re.DOTALL 匹配多行

使用 re.DOTALL 标志符,使 . 能够匹配包括换行符在内的所有字符,通常用于匹配跨多行的文本。

示例:

import re
text = "line1\nline2"
# 不使用 DOTALL,无法匹配换行符
result = re.findall(r'.+', text)
print(result)  # 输出: ['line1', 'line2']

# 使用 DOTALL,可以匹配换行符
result = re.findall(r'.+', text, re.DOTALL)
print(result)  # 输出: ['line1\nline2']

(七)匹配指定开头或结尾的多个字符

使用 ^ 表示匹配字符串的开头,$ 表示匹配字符串的结尾。例如 ^abc 匹配以 abc 开头的字符串,abc$ 匹配以 abc 结尾的字符串。

示例:

import re
text = "abc123abc"
# 匹配以 abc 开头的字符串
result = re.findall(r'^abc', text)
print(result)  # 输出: ['abc']

# 匹配以 abc 结尾的字符串
result = re.findall(r'abc$', text)
print(result)  # 输出: ['abc']

(八)匹配字母、数字、空白符

  • 使用 \w+ 匹配多个字母、数字或下划线字符。

  • 使用 \d+ 匹配多个数字。

  • 使用 \s+ 匹配多个空白字符(如空格、制表符、换行符)。

示例:

import re
text = "abc 123"
# 匹配多个字母或数字
result = re.findall(r'\w+', text)
print(result)  # 输出: ['abc', '123']

# 匹配多个空格
result = re.findall(r'\s+', text)
print(result)  # 输出: [' ']

(九)匹配多个字符总结

正则表达式可以通过使用量词、字符集和特殊符号来匹配多个字符。无论是匹配任意字符、特定字符、字符集,还是根据字符出现次数来匹配,正则表达式都可以提供灵活和强大的解决方案。熟练掌握这些技巧后,你可以有效处理多种文本处理需求。


二、匹配开头和结尾

在正则表达式中,使用 ^$ 分别可以匹配字符串的开头和结尾。它们的具体用法如下:

(一)匹配字符串的开头:^

^ 用于匹配字符串的开头。只有当字符串以指定的模式开头时,才会匹配成功。

示例: 假设我们想匹配以 "hello" 开头的字符串:

import re
text = "hello world"
result = re.findall(r'^hello', text)
print(result)  # 输出: ['hello']

如果字符串不是以 "hello" 开头,则匹配会失败:

text = "world hello"
result = re.findall(r'^hello', text)
print(result)  # 输出: []

(二)匹配字符串的结尾:$

$ 用于匹配字符串的结尾。只有当字符串以指定的模式结尾时,才会匹配成功。

示例: 假设我们想匹配以 "world" 结尾的字符串:

import re
text = "hello world"
result = re.findall(r'world$', text)
print(result)  # 输出: ['world']

如果字符串不是以 "world" 结尾,则匹配会失败:

text = "world hello"
result = re.findall(r'world$', text)
print(result)  # 输出: []

(三)同时匹配开头和结尾

可以结合 ^$ 同时使用,来匹配整个字符串的模式。例如,匹配完整的字符串 "hello world"

import re
text = "hello world"
result = re.findall(r'^hello world$', text)
print(result)  # 输出: ['hello world']

示例

import re
text = "hello world"
result = re.findall(r'^hello world$', text)
print(result)  # 输出: ['hello world']

这个模式要求整个字符串必须是 "hello world",否则匹配不会成功:

text = "hello world!"
result = re.findall(r'^hello world$', text)
print(result)  # 输出: []

(四)匹配多行模式

默认情况下,^$ 只会匹配整个字符串的开头和结尾。如果要在多行字符串中分别匹配每一行的开头和结尾,可以使用 re.MULTILINE 标志。

示例

import re
text = """hello world
goodbye world"""
# 匹配每行的开头为 'hello' 或 'goodbye'
result = re.findall(r'^(hello|goodbye)', text, re.MULTILINE)
print(result)  # 输出: ['hello', 'goodbye']

在这种情况下,^$ 会作用于每一行的起始和结束位置,而不仅仅是整个字符串的起始和结束。

(五)示例:验证电子邮件

假设我们需要验证电子邮件地址的格式,要求它以字母或数字开头,包含 @,并以域名结尾。可以结合 ^$ 来确保整个字符串符合电子邮件格式:

import re
email = "user@example.com"
pattern = r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'
result = re.match(pattern, email)
if result:
    print("有效的电子邮件地址")
else:
    print("无效的电子邮件地址")

(六)匹配开头和结尾总结

 匹配开头和结尾总结起来有以下几点:

  • ^ 用于匹配字符串的开头。

  • $ 用于匹配字符串的结尾。

  • re.MULTILINE 标志可以使 ^$ 作用于每一行的开头和结尾,而不仅限于整个字符串。

  • 结合 ^$ 可以确保整个字符串完全匹配特定的模式。


三、匹配分组

正则表达式中的分组功能可以通过使用圆括号 () 来实现,分组的作用是将表达式的某一部分进行分组匹配,并可以通过分组提取具体的匹配结果。分组是正则表达式非常强大的功能,允许我们对匹配的结果进行更灵活的操作。

(一)基本分组

使用圆括号 () 来将正则表达式中的某个部分进行分组。分组的内容会被单独提取出来,分组后可以通过 Match 对象的 .group().groups() 方法来获取匹配的分组内容。

示例:匹配并提取姓名和年龄

import re
text = "姓名: 张三, 年龄: 25"
# 使用分组来分别匹配姓名和年龄
pattern = r"姓名:\s(\w+),\s年龄:\s(\d+)"
result = re.search(pattern, text)

if result:
    print(result.group(1))  # 输出: 张三
    print(result.group(2))  # 输出: 25

在上面的例子中,正则表达式中的两个括号分别对名字和年龄进行了分组,因此可以通过 group(1)group(2) 来获取第一个和第二个匹配的分组。

(二)命名分组

命名分组允许你为分组指定一个名字,这样你可以通过分组名称来访问匹配结果,而不是使用数字索引。命名分组的语法是 (?P<name>...),其中 name 是分组的名字。

示例:使用命名分组提取姓名和年龄

import re
text = "姓名: 李四, 年龄: 30"
# 使用命名分组为姓名和年龄命名
pattern = r"姓名:\s(?P<name>\w+),\s年龄:\s(?P<age>\d+)"
result = re.search(pattern, text)

if result:
    print(result.group("name"))  # 输出: 李四
    print(result.group("age"))   # 输出: 30

在这种方式下,你可以通过分组的名称 nameage 来提取匹配的内容,代码更加清晰。

(三)非捕获分组

有时我们只想对表达式进行分组,而不希望捕获这个分组的匹配结果。可以使用 (?:...) 来创建一个非捕获分组。这样该分组参与匹配,但不会出现在匹配的结果中。

示例:使用非捕获分组

import re
text = "apple, banana, cherry"
# 使用非捕获分组来匹配不同的水果
pattern = r"(?:apple|banana|cherry)"
result = re.findall(pattern, text)
print(result)  # 输出: ['apple', 'banana', 'cherry']

在这个例子中,(?:...) 只是用来匹配,但不会被作为分组结果提取。

(四)使用 groups() 提取所有分组

使用 groups() 可以一次性提取所有分组的匹配内容,返回的是一个包含所有分组内容的元组。

示例:提取所有分组内容

import re
text = "姓名: 王五, 年龄: 40"
pattern = r"姓名:\s(\w+),\s年龄:\s(\d+)"
result = re.search(pattern, text)

if result:
    print(result.groups())  # 输出: ('王五', '40')

这里 groups() 返回了一个包含所有匹配的元组,分别是姓名和年龄。

(五)反向引用分组

  • 正则表达式允许在匹配时引用前面匹配到的分组内容。这通常用于验证某些内容的重复,例如匹配重复的字符或词组。

  • 反向引用的语法是 \1, \2 等,其中数字表示对应的分组。

示例:匹配重复的单词

import re
text = "hello hello world"
# 使用反向引用匹配重复的单词
pattern = r"(\b\w+\b)\s+\1"
result = re.search(pattern, text)

if result:
    print(result.group())  # 输出: hello hello

在这个例子中,(\b\w+\b) 匹配了一个单词,\1 引用了第一个分组的内容,从而匹配重复的单词。

(六)分组嵌套

分组可以嵌套使用,内层的分组优先级高,嵌套的分组也会有索引。

示例:嵌套分组

import re
text = "I have 2 apples and 3 oranges."
# 匹配数量和水果类型,使用嵌套分组
pattern = r"(\d+) (apples|oranges)"
result = re.findall(pattern, text)
print(result)  # 输出: [('2', 'apples'), ('3', 'oranges')]

在这个例子中,外层分组 (\d+) 匹配数量,内层分组 (apples|oranges) 匹配水果类型,最终通过 findall() 返回所有匹配项。

(七)忽略大小写和多行分组匹配

如果想在分组匹配时忽略大小写或处理多行匹配,可以使用 re.IGNORECASEre.MULTILINE 等标志。

示例:忽略大小写的分组匹配

import re
text = "HELLO world"
# 使用 re.IGNORECASE 忽略大小写
pattern = r"(hello) (world)"
result = re.search(pattern, text, re.IGNORECASE)

if result:
    print(result.groups())  # 输出: ('HELLO', 'world')

(八)匹配分组总结

分组在正则表达式中非常强大,既可以捕获匹配结果,也可以通过命名分组来提高代码的可读性。非捕获分组可以避免捕获不必要的信息,而反向引用则能够对重复内容进行验证。掌握分组的这些技巧可以极大增强正则表达式处理复杂文本的能力。


四、总结

正则表达式提供了一种简洁高效的方式来匹配和处理文本。本篇文章通过多个实际示例,展示了如何匹配多个字符、匹配字符串的开头和结尾,以及如何灵活运用分组来提取数据。在掌握了这些基本用法后,读者可以轻松应对各种复杂的文本处理任务。正则表达式虽然语法相对简洁,但功能极其强大。通过熟练运用分组、反向引用、命名分组等高级技巧,开发者可以显著提高代码的灵活性与可读性。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值