自学内容网 自学内容网

正则表达式

正则表达式(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():按正则表达式分割字符串。
示例:
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) 返回第二个捕获组,以此类推。
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),即整个匹配)。
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. 命名捕获组

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

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() 会返回一个包含捕获组名称和匹配内容的字典。
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():返回匹配到的字符串在原始字符串中的结束位置。
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():返回匹配的起始和结束位置
  • 返回一个元组,包含匹配到的字符串的起始位置和结束位置。
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:匹配的结束位置(搜索时传递给函数的结束位置)。
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 属性返回编译的正则表达式对象。
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 属性返回进行匹配的原始字符串。
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. 代码结构清晰:将正则表达式编译成对象后,能够使代码逻辑更清晰,特别是需要多次使用相同正则表达式时。

语法:

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

示例:

1. 使用 re.compile() 编译正则表达式:
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. 编译后进行多次操作:
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. 使用标志参数:
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'>

五、非贪婪匹配

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

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>'

原文地址:https://blog.csdn.net/a13545564067/article/details/142340338

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!