正则表达式

正则表达式(Regular Expression,简称 regexregexp)是用于匹配字符串的一种模式表达式,常用于文本搜索、替换、提取等任务。下面介绍正则表达式的常用方法及其典型应用。

一、正则表达式字符

正则表达式中的字符主要分为 普通字符特殊字符(元字符)。下面将对这两类字符分别进行详细解释。

1. 普通字符

普通字符就是那些在正则表达式中没有特殊意义的字符,它们表示字面上的含义,直接匹配字符串中的这些字符本身。

常见的普通字符:
  • 字母 :如 abc 等,直接匹配对应的字母。
  • 数字 :如 012 等,直接匹配对应的数字。
  • 标点符号 :如 ,!@ 等,如果它们没有在元字符列表中,直接匹配这些符号。
  • 其他字符 :例如空格、下划线 _、加号 + 等,通常也被视为普通字符,除非它们出现在特定的上下文中。

2. 特殊字符(元字符)

元字符在正则表达式中具有特殊的含义,控制匹配行为。要匹配元字符的字面含义,需要对其进行转义 ,即在其前面加上反斜杠 \

常见的元字符及其含义:
元字符 含义 举例
. 匹配除换行符外的任何单个字符 a.b 可以匹配 aab、acb、a1b 等,但不能匹配 ab
^ 匹配字符串的开头 ^abc 只匹配以 abc 开头的字符串,如 abc123
$ 匹配字符串的结尾 xyz$ 只匹配以 xyz 结尾的字符串,如 123xyz
* 匹配前一个字符 0 次或多次(贪婪匹配) ab*c 可以匹配 ac、abc、abbc、abbbc 等
+ 匹配前一个字符 1 次或多次(贪婪匹配) ab+c 可以匹配 abc、abbc、abbbc,但不匹配 ac(因为至少需要一个 b)
? 匹配前一个字符 0 次或 1 次(可选项)或使量词变为非贪婪模式 colou?r 可以匹配 color 和 colour
{} 限定前一个字符出现的次数 {m} 或出现的范围 {m,n} a{2,4} 匹配2到4个连续的 a,如 aa、aaa、aaaa
[] 字符类,匹配方括号中的任意一个字符 [abc] 匹配 a、b 或 c
` ` 或运算符,匹配其左右两边的任意一个表达式
() 捕获组,分组子表达式,并捕获匹配到的文本 (abc)+ 匹配 abc、abcabc 等
\ 转义符,用于转义元字符或表示特殊序列(如 \d 表示数字) . 可以匹配点号 .,因为 . 本身是元字符,转义后才能表示真正的点号
常见的转义字符和特殊序列:
转义字符/特殊序列 含义
\d 匹配任何数字字符(等同于 [0-9]
\D 匹配任何非数字字符(等同于 [^0-9]
\w 匹配任何字母、数字或下划线(等同于 [A-Za-z0-9_]
\W 匹配任何非字母、数字或下划线字符(等同于 [^A-Za-z0-9_]
\s 匹配任何空白字符(空格、制表符、换行符等)
\S 匹配任何非空白字符
\b 匹配单词边界
\B 匹配非单词边界
\t 匹配制表符
\n 匹配换行符
\r 匹配回车符
\f 匹配换页符

3. 字符类

字符类用方括号 [] 表示,表示匹配括号内任意一个字符。可以使用连字符 - 表示字符范围。

示例:
  • [abc]:匹配 abc
  • [a-z]:匹配所有小写字母。
  • [A-Z]:匹配所有大写字母。
  • [0-9]:匹配所有数字。
  • [^abc]:匹配除 abc 以外的任意字符(注意方括号中的 ^ 表示取反)。

4. 量词

量词用于指定前一个字符或子表达式的重复次数。

量词 含义
* 匹配前面的字符 0 次或多次
+ 匹配前面的字符 1 次或多次
? 匹配前面的字符 0 次或 1 次
{n} 匹配前面的字符恰好 n
{n,} 匹配前面的字符至少 n
{n,m} 匹配前面的字符至少 n 次,最多 m

5. 锚点

锚点用于匹配文本中的特定位置,而不是字符。

  • ^:匹配字符串的开头。
  • $:匹配字符串的结尾。
  • \b:匹配单词的边界。
  • \B:匹配非单词边界。

二、正则表达式用法

1. 基本用法:匹配与查找

在编程语言中使用正则表达式时,通常会使用一些专门的函数或方法来处理正则表达式。以 Python 中的 re 模块为例:

基本函数:
  • re.match() :从字符串的开头开始匹配,若匹配成功,返回 Match 对象;否则返回 None
  • re.search() :在整个字符串中搜索,返回第一次成功匹配的 Match 对象;否则返回 None
  • re.findall():返回所有匹配的子串,以列表形式输出。
  • re.finditer() :返回所有匹配子串的迭代器,每个匹配都包含 Match 对象。
  • re.sub():用于替换匹配到的字符串。
  • re.split():按正则表达式分割字符串。
示例:
python 复制代码
import re

# 示例字符串
text = "There are 3 apples and 5 oranges."
pattern = r"\d+"

# 1. re.match() 示例:匹配字符串开头
result = re.match(r"There", text)
print(result.group())  # 输出 'There'

# 2. re.search() 示例:查找字符串中的第一个数字
result = re.search(pattern, text)
print(result.group())  # 输出 '3'

# 3. re.findall() 示例:查找所有数字
phones = re.findall(pattern, text)
print(phones)  # 输出 ['3', '5']

# 4. re.sub() 示例:替换数字为 [NUM]
redacted_text = re.sub(pattern, "[NUM]", text)
print(redacted_text)  # 输出 'There are [NUM] apples and [NUM] oranges.'

# 5. re.split() 示例:按空白字符分割字符串
result = re.split(r"\s+", text)
print(result)  # 输出 ['There', 'are', '3', 'apples', 'and', '5', 'oranges.']

三、Match对象

Match 对象是 Python 正则表达式库 re 中返回的一个结果对象,当使用 re.match()re.search()re.finditer() 成功匹配字符串时,返回的就是这个对象。Match 对象包含了有关匹配结果的各种信息,并提供了一些方法和属性来访问匹配的内容和位置。

Match 对象的常用方法和属性

1. group():获取匹配的内容
  • group(0)group():返回整个匹配的字符串。
  • group(n) :返回第 n 个捕获组的匹配内容。使用括号 () 创建捕获组,group(1) 返回第一个捕获组,group(2) 返回第二个捕获组,以此类推。
python 复制代码
import re

text = "My phone number is 123-456-7890."
pattern = r'(\d{3})-(\d{3})-(\d{4})'

match = re.search(pattern, text)

if match:
    print(match.group(0))  # 输出 '123-456-7890',整个匹配的字符串
    print(match.group(1))  # 输出 '123',第一个捕获组
    print(match.group(2))  # 输出 '456',第二个捕获组
    print(match.group(3))  # 输出 '7890',第三个捕获组
2. groups():获取所有捕获组的元组
  • 返回一个包含所有捕获组的元组(不包含 group(0),即整个匹配)。
python 复制代码
import re

text = "Date: 2024-09-18"
pattern = r"(\d{4})-(\d{2})-(\d{2})"

match = re.search(pattern, text)
if match:
    print(match.groups())  # 输出 ('2024', '09', '18')
3. 命名捕获组

使用命名捕获组可以给捕获的内容命名,便于后续引用。

python 复制代码
import re

text = "Order number: 12345, Date: 2024-01-01"
pattern = r"Order number: (?P<order>\d+), Date: (?P<date>\d{4}-\d{2}-\d{2})"
match = re.search(pattern, text)
print(match.group("order"))  # 输出 '12345'
print(match.group("date"))   # 输出 '2024-01-01'
具体解释:
  • Order number: :匹配字符串的开头部分,要求它包含 Order number: 这个固定的文本。

  • (?P<order>\d+):这是一个命名捕获组,捕获订单号。具体来说:

    • (?P<order>...):捕获组,并命名为 order,捕获的内容可以通过 group("order") 访问。
    • \d+:匹配一个或多个数字字符,即订单号部分(12345)。
  • , Date: :匹配订单号后的固定文本 , Date:

  • (?P<date>\d{4}-\d{2}-\d{2}):这是另一个命名捕获组,捕获日期。具体来说:

    • (?P<date>...):捕获组,并命名为 date,捕获的内容可以通过 group("date") 访问。
    • \d{4}:匹配四位数字(年份部分,2024)。
    • -:匹配一个 - 符号(日期的分隔符)。
    • \d{2}:匹配两位数字(月份和日期部分,0101)。

整个正则表达式模式匹配的字符串结构是:

Order number: 12345, Date: 2024-01-01
4. groupdict():返回命名捕获组的字典
  • 如果正则表达式中使用了命名捕获组(通过 (?P<name>...) 的语法),groupdict() 会返回一个包含捕获组名称和匹配内容的字典。
python 复制代码
import re

text = "Order number: 12345, Date: 2024-09-18"
pattern = r"Order number: (?P<order>\d+), Date: (?P<date>\d{4}-\d{2}-\d{2})"

match = re.search(pattern, text)
if match:
    print(match.groupdict())  # 输出 {'order': '12345', 'date': '2024-09-18'}
5. start()end():匹配位置
  • start():返回匹配到的字符串在原始字符串中的起始位置。
  • end():返回匹配到的字符串在原始字符串中的结束位置。
python 复制代码
import re

text = "My phone number is 123-456-7890."
pattern = r'\d{3}-\d{3}-\d{4}'

match = re.search(pattern, text)

if match:
    print(match.start())  # 输出 19,匹配到的字符串开始的位置
    print(match.end())    # 输出 31,匹配到的字符串结束的位置
6. span():返回匹配的起始和结束位置
  • 返回一个元组,包含匹配到的字符串的起始位置和结束位置。
python 复制代码
import re

text = "My phone number is 123-456-7890."
pattern = r'\d{3}-\d{3}-\d{4}'

match = re.search(pattern, text)

if match:
    print(match.span())  # 输出 (19, 31),匹配到的字符串在原始字符串中的起止位置
7. posendpos:匹配范围的起始和结束位置
  • pos:匹配的开始位置(搜索时传递给函数的起始位置)。
  • endpos:匹配的结束位置(搜索时传递给函数的结束位置)。
python 复制代码
import re

text = "My phone number is 123-456-7890."
pattern = r'\d{3}-\d{3}-\d{4}'

match = re.search(pattern, text)

if match:
    print(match.pos)     # 输出 0,匹配搜索的起始位置
    print(match.endpos)  # 输出 31,匹配搜索的结束位置
8. re:返回使用的正则表达式
  • re 属性返回编译的正则表达式对象。
python 复制代码
import re

pattern = r'\d{3}-\d{3}-\d{4}'
match = re.search(pattern, "My phone number is 123-456-7890.")

if match:
    print(match.re)  # 输出 re.compile('\\d{3}-\\d{3}-\\d{4}')
9. string:返回匹配的字符串
  • string 属性返回进行匹配的原始字符串。
python 复制代码
import re

pattern = r'\d{3}-\d{3}-\d{4}'
match = re.search(pattern, "My phone number is 123-456-7890.")

if match:
    print(match.string)  # 输出 'My phone number is 123-456-7890.'

四、re.compile()

在 Python 中,re.compile() 是用于编译正则表达式 的函数。它将一个正则表达式字符串编译成一个正则表达式对象,这个对象可以用于多次执行匹配操作,提升性能并简化代码结构。

使用 re.compile() 的好处:

  1. 提高性能 :当你在代码中需要多次使用同一个正则表达式时,使用 re.compile() 预先编译正则表达式可以提高效率,避免重复解析正则表达式。
  2. 代码结构清晰:将正则表达式编译成对象后,能够使代码逻辑更清晰,特别是需要多次使用相同正则表达式时。

语法:

python 复制代码
pattern = re.compile(r'正则表达式', flags)
  • pattern:表示编译后的正则表达式对象。
  • r'正则表达式' :待编译的正则表达式字符串,通常使用原始字符串(r'')来防止转义字符的问题。
  • flags :可选参数,用于指定匹配行为的标志(如忽略大小写、支持多行等)。常见标志包括:
    • re.IGNORECASE (re.I):忽略大小写匹配。
    • re.MULTILINE (re.M):多行模式,让 ^$ 匹配每一行的开头和结尾。
    • re.DOTALL (re.S):使 . 匹配所有字符,包括换行符。

示例:

1. 使用 re.compile() 编译正则表达式:
python 复制代码
import re

# 编译一个匹配电子邮件的正则表达式
email_pattern = re.compile(r'[\w\.-]+@[\w\.-]+\.\w+')

# 使用编译后的模式多次匹配不同的字符串
email1 = "user1@example.com"
email2 = "user2@domain.org"

# 使用 compiled 正则表达式对象的 match() 方法
print(email_pattern.match(email1))  # 输出 <re.Match object; span=(0, 17), match='user1@example.com'>
print(email_pattern.match(email2))  # 输出 <re.Match object; span=(0, 16), match='user2@domain.org'>
2. 编译后进行多次操作:
python 复制代码
import re

# 编译一个匹配数字的正则表达式
number_pattern = re.compile(r'\d+')

text = "There are 123 apples and 456 oranges."

# 使用 compiled 正则表达式对象的 findall() 方法
numbers = number_pattern.findall(text)
print(numbers)  # 输出 ['123', '456']
3. 使用标志参数:
python 复制代码
import re

# 编译一个忽略大小写的正则表达式
pattern = re.compile(r'hello', re.IGNORECASE)

text1 = "Hello World"
text2 = "hello world"

# 匹配忽略大小写的字符串
print(pattern.search(text1))  # 输出 <re.Match object; span=(0, 5), match='Hello'>
print(pattern.search(text2))  # 输出 <re.Match object; span=(0, 5), match='hello'>

五、非贪婪匹配

默认情况下,正则表达式是贪婪匹配 的,即尽可能多地匹配字符。可以通过在量词后面加 ? 来进行非贪婪匹配

python 复制代码
text = "<html><title>My Page</title></html>"
greedy_pattern = r"<.*>"  # 贪婪匹配
non_greedy_pattern = r"<.*?>"  # 非贪婪匹配

# 贪婪匹配:会匹配整个字符串,因为它尝试匹配尽可能多的字符
print(re.search(greedy_pattern, text).group())  # 输出 '<html><title>My Page</title></html>'

# 非贪婪匹配:会匹配到第一个闭合标签
print(re.search(non_greedy_pattern, text).group())  # 输出 '<html>'
相关推荐
ROCKY_81736 分钟前
Mysql复习(二)
数据库·mysql·oracle
Dovir多多1 小时前
Python数据处理——re库与pydantic的使用总结与实战,处理采集到的思科ASA防火墙设备信息
网络·python·计算机网络·安全·网络安全·数据分析
问道飞鱼3 小时前
【知识科普】认识正则表达式
数据库·mysql·正则表达式
HaiFan.3 小时前
SpringBoot 事务
java·数据库·spring boot·sql·mysql
水根LP493 小时前
linux系统上SQLPLUS的重“大”发现
数据库·oracle
沐霜枫叶3 小时前
解决pycharm无法识别miniconda
ide·python·pycharm
途途途途4 小时前
精选9个自动化任务的Python脚本精选
数据库·python·自动化
蓝染然4 小时前
jax踩坑指南——人类早期驯服jax实录
python
许野平4 小时前
Rust: enum 和 i32 的区别和互换
python·算法·rust·enum·i32
问道飞鱼4 小时前
【Python知识】Python进阶-什么是装饰器?
开发语言·python·装饰器