本文最后更新于 2025-02-10,墨迹未干时,知识正鲜活。随着时间推移,文章部分内容可能需要重新着墨,请您谅解。Contact

正则表达式语法详解

基本字符

  • 普通字符: 大部分字符(字母、数字等)都表示它们自身。例如,a 匹配字母 "a",1 匹配数字 "1"。
  • . (点号): 匹配除换行符 (\n) 之外的任何单个字符。
  • \ (反斜杠):
    • 转义字符: 用于匹配特殊字符本身。例如,\. 匹配点号 ".",\\ 匹配反斜杠 ""。
    • 特殊序列: 与某些字母结合,表示特定字符类别。例如,\d 匹配任何数字,\s 匹配任何空白字符。

字符集

  • [...] (方括号): 匹配方括号内的任何一个字符。
    • 例如:[abc] 匹配 "a"、"b" 或 "c"。
    • 范围表示:[a-z] 匹配任何小写字母,[0-9] 匹配任何数字。
    • 排除字符:[^abc] 匹配除 "a"、"b" 和 "c" 之外的任何字符。

量词 (Quantifiers)

  • *: 匹配前面的字符零次或多次。
  • +: 匹配前面的字符一次或多次。
  • ?: 匹配前面的字符零次或一次。
  • {n}: 匹配前面的字符恰好 n 次。
  • {n,}: 匹配前面的字符至少 n 次。
  • {n,m}: 匹配前面的字符 n 到 m 次 (包含 n 和 m)。

边界匹配

  • ^: 匹配字符串的开头。
  • $: 匹配字符串的结尾。
  • \b: 匹配单词边界 (单词字符和非单词字符之间的位置)。
  • \B: 匹配非单词边界。

分组和捕获

  • (...) (圆括号):
    • 分组:将多个字符视为一个整体,可以对分组应用量词。
    • 捕获:将括号内匹配的内容保存起来,供后续引用 (通过 \1, \2 等)。

| 或 (Alternation)

  • |: 匹配竖线两侧的任意一个表达式。例如,cat|dog 匹配 "cat" 或 "dog"。

特殊序列

  • \d: 匹配任何数字,等价于 [0-9]
  • \D: 匹配任何非数字字符,等价于 [^0-9]
  • \w: 匹配任何字母、数字或下划线,等价于 [a-zA-Z0-9_]
  • \W: 匹配任何非字母、数字或下划线字符,等价于 [^a-zA-Z0-9_]
  • \s: 匹配任何空白字符 (空格、制表符、换行符等)。
  • \S: 匹配任何非空白字符。

Python 中的正则表达式 (re 模块)

Python 的 re 模块提供了对正则表达式的支持。常用的函数:

  • re.compile(pattern, flags=0): 将正则表达式编译成一个模式对象,可以提高匹配效率。
  • re.search(pattern, string, flags=0): 在字符串中搜索第一个匹配项,返回一个匹配对象 (match object) 或 None
  • re.match(pattern, string, flags=0): 从字符串的开头开始匹配,返回一个匹配对象或 None
  • re.findall(pattern, string, flags=0): 查找字符串中所有非重叠的匹配项,返回一个列表。
  • re.finditer(pattern, string, flags=0): 查找字符串中所有非重叠的匹配项,返回一个迭代器,每个元素是一个匹配对象。
  • re.sub(pattern, repl, string, count=0, flags=0): 将字符串中所有匹配的子串替换为 repl (可以是字符串或函数)。
  • re.split(pattern, string, maxsplit=0, flags=0): 使用正则表达式作为分隔符来分割字符串。

标志 (Flags)

re 模块的函数通常接受一个可选的 flags 参数,用来修改正则表达式的行为。常用标志:

  • re.IGNORECASE (或 re.I): 忽略大小写。
  • re.MULTILINE (或 re.M): 多行模式,使 ^$ 匹配每一行的开头和结尾。
  • re.DOTALL (或 re.S): 使 . 匹配任何字符,包括换行符。

匹配对象 (Match Object)

re.search(), re.match(), re.finditer() 返回匹配对象,它包含有关匹配的信息:

  • group(n=0): 返回第 n 个捕获组的文本 (n=0 表示整个匹配)。
  • groups(): 返回所有捕获组的文本,以元组形式。
  • start(n=0): 返回第 n 个捕获组的起始索引。
  • end(n=0): 返回第 n 个捕获组的结束索引。
  • span(n=0): 返回第 n 个捕获组的起始和结束索引,以元组形式 (start, end)

Python 文本编辑示例

import re

text = """
This is a sample text with some email addresses:
[email protected], [email protected]

And some phone numbers:
123-456-7890, (555) 123-4567
"""

# 1. 查找所有电子邮件地址
email_pattern = r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
emails = re.findall(email_pattern, text)
print("Emails:", emails)  # 输出: ['[email protected]', '[email protected]']

# 2. 查找所有电话号码
phone_pattern = r"(\d{3}[-\s]?\d{3}[-\s]?\d{4}|\(\d{3}\)\s?\d{3}[-\s]?\d{4})"  # 两种格式
phones = re.finditer(phone_pattern, text)
print("Phone Numbers:")
for phone in phones:
    print(phone.group())  # 输出: 123-456-7890 和 (555) 123-4567

# 3. 将电话号码格式统一为 xxx-xxx-xxxx
def format_phone(match):
    num = match.group()
    num = re.sub(r"\D", "", num)  # 移除所有非数字字符
    return f"{num[:3]}-{num[3:6]}-{num[6:]}"

formatted_text = re.sub(phone_pattern, format_phone, text)
print("\nFormatted Text:\n", formatted_text)

# 4. 提取域名
domain_pattern = r"@([a-zA-Z0-9.-]+)\." #用括号提取
domains = []
for email in emails:
    match = re.search(domain_pattern, email)
    if match:
        domains.append(match.group(1))  # 使用 group(1) 获取第一个捕获组
print("\nDomains:", domains)  # 输出: ['example.com', 'domain.net']

# 5. 将文本中的所有数字替换为 "NUM"
replaced_text = re.sub(r"\d+", "NUM", text)
print("\nReplaced Text:\n", replaced_text)

#6.  HTML 标签提取
html_text = "<p>This is a <b>bold</b> word and <i>italic</i>.</p>"
tag_content_pattern = r"<[^>]+>([^<]+)</[^>]+>"  # 匹配标签内的内容
# 或者更简单的非贪婪模式:
# tag_content_pattern = r"<.+?>(.+?)</.+?>"
matches = re.findall(tag_content_pattern, html_text)
print("\nTag Contents:", matches) # 输出:['This is a ', 'bold', ' word and ', 'italic', '.']  注意,这个例子有局限性,更复杂的 HTML 需要 HTML 解析器

#7. 验证密码强度 (示例)
def is_strong_password(password):
    pattern = r"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"
    # 至少 8 个字符
    # 至少包含一个小写字母
    # 至少包含一个大写字母
    # 至少包含一个数字
    # 至少包含一个特殊字符
    return bool(re.match(pattern, password))

print("\nPassword Strength:")
print("Password123:", is_strong_password("Password123"))    # False
print("StrongP@ss1:", is_strong_password("StrongP@ss1"))    # True
print("Short1:", is_strong_password("Short1"))          # False