第97集:re模块:正则表达式基础

学习目标

  • 理解正则表达式的基本概念和作用
  • 掌握Python中re模块的基本使用方法
  • 学习正则表达式的基本语法规则
  • 能够使用正则表达式进行简单的字符串匹配操作

一、什么是正则表达式?

正则表达式(Regular Expression,简称Regex或RegExp)是一种用于描述字符串模式的特殊语法,它可以帮助我们:

  1. 匹配特定模式的字符串
  2. 查找字符串中的特定内容
  3. 替换字符串中的特定部分
  4. 分割字符串

正则表达式广泛应用于文本处理、数据验证、信息提取等场景。

二、Python中的re模块

Python提供了内置的re模块,用于处理正则表达式。使用前需要先导入:

import re

三、正则表达式的基本语法

1. 普通字符

普通字符包括字母、数字、空格等,它们在正则表达式中表示自身:

  • a 匹配字符"a"
  • 123 匹配字符串"123"
  • hello 匹配字符串"hello"

2. 元字符

元字符是正则表达式中具有特殊含义的字符:

元字符 含义 示例
. 匹配任意单个字符(除了换行符) a.b 匹配 "acb"、"a1b"、"a b" 等
^ 匹配字符串的开头 ^hello 匹配以 "hello" 开头的字符串
$ 匹配字符串的结尾 world$ 匹配以 "world" 结尾的字符串
* 匹配前面的字符0次或多次 ab*c 匹配 "ac"、"abc"、"abbc" 等
+ 匹配前面的字符1次或多次 ab+c 匹配 "abc"、"abbc" 等
? 匹配前面的字符0次或1次 ab?c 匹配 "ac"、"abc"
{n} 匹配前面的字符恰好n次 ab{3}c 匹配 "abbbc"
{n,} 匹配前面的字符至少n次 ab{2,}c 匹配 "abbc"、"abbbc" 等
{n,m} 匹配前面的字符n到m次 ab{1,3}c 匹配 "abc"、"abbc"、"abbbc"
[] 字符类,匹配括号内的任意一个字符 [abc] 匹配 "a"、"b" 或 "c"
\ 转义字符,用于匹配特殊字符本身 \. 匹配 ",\\ 匹配 ""
` ` 或运算符,匹配左右任意一个表达式
() 分组,将多个字符作为一个整体 (ab)+ 匹配 "ab"、"abab" 等

3. 字符类

字符类用于匹配指定范围内的字符:

字符类 含义
[abc] 匹配 "a"、"b" 或 "c"
[a-z] 匹配任意小写字母
[A-Z] 匹配任意大写字母
[0-9] 匹配任意数字
[a-zA-Z] 匹配任意字母
[a-zA-Z0-9] 匹配任意字母或数字
[^abc] 匹配除了 "a"、"b"、"c" 之外的任意字符

4. 预定义字符类

为了方便使用,正则表达式提供了一些预定义的字符类:

预定义字符类 含义 等价于
\d 匹配任意数字 [0-9]
\D 匹配任意非数字 [^0-9]
\w 匹配任意字母、数字或下划线 [a-zA-Z0-9_]
\W 匹配任意非字母、数字或下划线 [^a-zA-Z0-9_]
\s 匹配任意空白字符(空格、制表符、换行符等) [ \t\n\r\f\v]
\S 匹配任意非空白字符 [^ \t\n\r\f\v]

5. 量词的贪婪与非贪婪

默认情况下,量词是贪婪的,会尽可能多地匹配字符。在量词后面加上?可以使其变为非贪婪模式:

  • .* 贪婪匹配:匹配尽可能多的字符
  • .*? 非贪婪匹配:匹配尽可能少的字符

四、re模块的常用函数

1. re.match()

re.match() 尝试从字符串的开头匹配一个模式:

import re

# 匹配成功
result = re.match(r'hello', 'hello world')
print(result)  # <re.Match object; span=(0, 5), match='hello'>
print(result.group())  # hello
print(result.span())  # (0, 5)

# 匹配失败
result = re.match(r'world', 'hello world')
print(result)  # None

2. re.search()

re.search() 在整个字符串中查找第一个匹配的模式:

import re

result = re.search(r'world', 'hello world')
print(result)  # <re.Match object; span=(6, 11), match='world'>
print(result.group())  # world

3. re.findall()

re.findall() 查找字符串中所有匹配的模式,返回一个列表:

import re

result = re.findall(r'\d+', 'There are 123 apples and 456 oranges')
print(result)  # ['123', '456']

4. re.split()

re.split() 根据匹配的模式分割字符串:

import re

# 用逗号或空格分割字符串
result = re.split(r'[ ,]+', 'a,b c  d')
print(result)  # ['a', 'b', 'c', 'd']

5. re.sub()

re.sub() 替换字符串中匹配的模式:

import re

# 将所有数字替换为 "X"
result = re.sub(r'\d+', 'X', 'There are 123 apples and 456 oranges')
print(result)  # There are X apples and X oranges

6. re.compile()

re.compile() 编译正则表达式模式,提高多次使用的效率:

import re

# 编译模式
pattern = re.compile(r'\d+')

# 使用编译后的模式
result1 = pattern.findall('123 abc 456')
result2 = pattern.sub('X', '789 def 012')

print(result1)  # ['123', '456']
print(result2)  # X def X

五、分组

使用括号 () 可以将正则表达式的一部分分组,方便后续操作:

import re

# 匹配日期格式:YYYY-MM-DD
pattern = re.compile(r'(\d{4})-(\d{2})-(\d{2})')
result = pattern.match('2023-10-05')

if result:
    print(result.group())  # 2023-10-05 (完整匹配)
    print(result.group(1))  # 2023 (第1组)
    print(result.group(2))  # 10 (第2组)
    print(result.group(3))  # 05 (第3组)
    print(result.groups())  # ('2023', '10', '05') (所有组)

六、应用案例

1. 验证邮箱格式

import re

def is_valid_email(email):
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    return bool(re.match(pattern, email))

# 测试
print(is_valid_email('user@example.com'))  # True
print(is_valid_email('invalid-email'))  # False
print(is_valid_email('another.user@sub.example.org'))  # True

2. 提取URL

import re

def extract_urls(text):
    pattern = r'https?://[\w\-._~:/?#[\]@!$&\'()*+,;=.]+'
    return re.findall(pattern, text)

# 测试
text = 'Visit https://www.example.com or http://test.org for more info.'
print(extract_urls(text))  # ['https://www.example.com', 'http://test.org']

3. 替换电话号码格式

import re

def format_phone_number(phone):
    # 将电话号码格式化为 (XXX) XXX-XXXX
    pattern = r'(\d{3})(\d{3})(\d{4})'
    return re.sub(pattern, r'(\1) \2-\3', phone)

# 测试
print(format_phone_number('1234567890'))  # (123) 456-7890

七、最佳实践

  1. 使用原始字符串:在正则表达式前加上 r 表示原始字符串,避免转义字符的问题:

    # 推荐
    pattern = r'\d+'
    
    # 不推荐
    pattern = '\\d+'
  2. 编译正则表达式:如果需要多次使用同一个正则表达式,建议先编译:

    pattern = re.compile(r'\d+')
    result1 = pattern.findall(text1)
    result2 = pattern.findall(text2)
  3. 注意贪婪与非贪婪:根据需要选择合适的量词模式

  4. 测试正则表达式:使用在线工具(如regex101.com)测试正则表达式

  5. 保持正则表达式的可读性:复杂的正则表达式可以使用注释(通过 re.VERBOSE 标志)

八、总结

本集我们学习了:

  1. 正则表达式的基本概念和作用
  2. Python中re模块的导入和使用
  3. 正则表达式的基本语法(普通字符、元字符、字符类、量词等)
  4. re模块的常用函数(match、search、findall、split、sub、compile)
  5. 分组的使用方法
  6. 正则表达式的应用案例和最佳实践

正则表达式是一个强大的工具,但也需要不断练习才能熟练掌握。下一集我们将深入学习re模块的高级功能。

九、课后练习

  1. 编写一个正则表达式,匹配中国的手机号码(11位数字,以1开头)
  2. 使用正则表达式从以下文本中提取所有的IP地址:"Server 1: 192.168.1.1, Server 2: 10.0.0.1"
  3. 编写一个函数,将字符串中的多余空格替换为单个空格
  4. 使用正则表达式验证密码强度(至少8位,包含大小写字母和数字)

下一集预告:re模块:模式匹配(第98集)

« 上一篇 math模块详解 下一篇 » re模块:模式匹配