Python 正则表达式 re.findall()

发布于:2025-08-13 ⋅ 阅读:(14) ⋅ 点赞:(0)

re.findall() 是 Python re 模块中用于查找字符串中所有匹配正则表达式模式的子串的方法。与 re.search() 只返回第一个匹配项不同,findall() 会返回所有匹配项。

基本语法

re.findall(pattern, string, flags=0)

参数说明:

  • pattern: 正则表达式模式
  • string: 要搜索的字符串
  • flags: 可选标志,如 re.IGNORECASEre.MULTILINE

返回值:

  • 如果模式中有分组,返回分组元组的列表
  • 如果模式中没有分组,返回所有匹配子串的列表
  • 如果没有找到匹配,返回空列表

1. 基本查找用法

示例1:查找所有数字

import re

text = "There are 3 apples and 5 oranges"
numbers = re.findall(r'\d+', text)
print(numbers)  # 输出: ['3', '5']

示例2:查找所有单词

text = "Hello world! Python is awesome."
words = re.findall(r'\w+', text)
print(words)  # 输出: ['Hello', 'world', 'Python', 'is', 'awesome']

2. 使用分组时的行为

示例3:无分组情况

text = "John: 30, Jane: 25, Bob: 42"
ages = re.findall(r': \d+', text)
print(ages)  # 输出: [': 30', ': 25', ': 42']

示例4:有分组情况(返回分组内容)

text = "John: 30, Jane: 25, Bob: 42"
ages = re.findall(r': (\d+)', text)
print(ages)  # 输出: ['30', '25', '42']

示例5:多个分组情况

text = "John: 30, Jane: 25, Bob: 42"
info = re.findall(r'(\w+): (\d+)', text)
print(info)  # 输出: [('John', '30'), ('Jane', '25'), ('Bob', '42')]

3. 使用正则表达式高级特性

示例6:非贪婪匹配

html = "<div>content1</div><div>content2</div>"
contents = re.findall(r'<div>(.*?)</div>', html)
print(contents)  # 输出: ['content1', 'content2']

示例7:使用字符类

text = "Colors: red, green, BLUE, Yellow"
colors = re.findall(r'[a-zA-Z]+', text)
print(colors)  # 输出: ['Colors', 'red', 'green', 'BLUE', 'Yellow']

示例8:使用边界匹配

text = "cat category concatenate"
words = re.findall(r'\bcat\b', text)
print(words)  # 输出: ['cat']

4. 使用标志(flags)

示例9:忽略大小写

text = "Apple orange BANANA Grape"
fruits = re.findall(r'[a-z]+', text, re.IGNORECASE)
print(fruits)  # 输出: ['Apple', 'orange', 'BANANA', 'Grape']

示例10:多行模式

text = """First line
Second line
Third line"""
lines = re.findall(r'^\w+', text, re.MULTILINE)
print(lines)  # 输出: ['First', 'Second', 'Third']

5. 实际应用场景

示例11:提取电子邮件地址

text = "Contact us at info@example.com or support@test.org"
emails = re.findall(r'[\w\.-]+@[\w\.-]+', text)
print(emails)  # 输出: ['info@example.com', 'support@test.org']

示例12:提取URL链接

text = "Visit https://www.example.com or http://test.org"
urls = re.findall(r'https?://[^\s/$.?#].[^\s]*', text)
print(urls)  # 输出: ['https://www.example.com', 'http://test.org']

示例13:解析日志文件

log = """
2023-04-15 10:00:00 INFO System started
2023-04-15 10:01:23 ERROR Database connection failed
2023-04-15 10:02:45 WARNING Disk space low
"""
errors = re.findall(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} ERROR (.+)', log)
print(errors)  # 输出: ['Database connection failed']

示例14:提取HTML标签内容

html = "<h1>Title</h1><p>Paragraph 1</p><p>Paragraph 2</p>"
paragraphs = re.findall(r'<p>(.*?)</p>', html)
print(paragraphs)  # 输出: ['Paragraph 1', 'Paragraph 2']

示例15:提取电话号码

text = "Call 123-456-7890 or 987.654.3210"
phones = re.findall(r'\d{3}[-.]\d{3}[-.]\d{4}', text)
print(phones)  # 输出: ['123-456-7890', '987.654.3210']

示例16:提取货币金额

text = "Prices: $12.99, €9.99, ¥1000"
prices = re.findall(r'[\$€¥]\d+\.?\d*', text)
print(prices)  # 输出: ['$12.99', '€9.99', '¥1000']

示例17:提取日期

text = "Dates: 2023-04-15, 15/04/2023, 04.15.2023"
dates = re.findall(r'\d{4}[-/.]\d{2}[-/.]\d{2}|\d{2}[-/.]\d{2}[-/.]\d{4}', text)
print(dates)  # 输出: ['2023-04-15', '15/04/2023', '04.15.2023']

6. 高级技巧

示例18:使用命名分组

text = "User: john_doe, Age: 30; User: jane_smith, Age: 25"
users = re.findall(r'User: (?P<name>\w+), Age: (?P<age>\d+)', text)
print(users)  # 输出: [('john_doe', '30'), ('jane_smith', '25')]

示例19:复杂模式匹配

text = "Coordinates: (12.345, -67.890), (0, 42.123)"
coords = re.findall(r'\(([^,]+),\s*([^)]+)\)', text)
print(coords)  # 输出: [('12.345', '-67.890'), ('0', '42.123')]

示例20:使用正向预查

text = "apple orange banana grape"
fruits_before_banana = re.findall(r'\w+(?=\sbanana)', text)
print(fruits_before_banana)  # 输出: ['orange']

7. 注意事项

  1. re.findall() 返回的是字符串列表或元组列表,不是匹配对象
  2. 当模式中有分组时,只返回分组内容,不是整个匹配
  3. 对于大文本,考虑使用 re.finditer() 节省内存
  4. 复杂的正则表达式可能会影响性能
  5. 处理HTML/XML等结构化数据时,最好使用专门的解析器

示例21:与 re.finditer() 对比

text = "Error 404, Error 500, Warning 302"

# 使用 findall
codes = re.findall(r'Error (\d+)', text)
print(codes)  # 输出: ['404', '500']

# 使用 finditer
for match in re.finditer(r'Error (\d+)', text):
    print(f"Found at {match.start()}-{match.end()}: {match.group(1)}")
# 输出:
# Found at 0-8: 404
# Found at 10-18: 500

8. 性能优化建议

  1. 预编译常用正则表达式:

    pattern = re.compile(r'\d+')
    numbers = pattern.findall(text)
    
  2. 尽量使用具体模式而非宽泛模式:

    # 不好的写法
    re.findall(r'.*:\s*(.*)', text)
    
    # 更好的写法
    re.findall(r'\w+:\s*(\w+)', text)
    
  3. 避免过度使用回溯:

    # 可能导致性能问题的写法
    re.findall(r'(a+)+$', text)
    

Python re.findall() 方法中的 flags 参数详解

re.findall() 方法的 flags 参数可以修改正则表达式的匹配行为,使其更灵活地适应不同的文本处理需求。下面我将详细介绍各种 flag 的用法和实际应用场景。

1. 常用 flags 概览

标志常量 简写 描述
re.IGNORECASE re.I 忽略大小写
re.MULTILINE re.M 多行模式,影响 ^$
re.DOTALL re.S 使 . 匹配包括换行符在内的所有字符
re.VERBOSE re.X 允许编写更易读的正则表达式
re.ASCII re.A 使 \w, \W, \b, \B, \d, \D, \s, \S 只匹配 ASCII 字符
re.LOCALE re.L 使 \w, \W, \b, \B 依赖当前区域设置
re.UNICODE re.U 使 \w, \W, \b, \B, \d, \D, \s, \S 匹配 Unicode 字符

2. 各 flag 详细说明及示例

2.1 re.IGNORECASE (re.I) - 忽略大小写

作用:使匹配对大小写不敏感

示例

import re

text = "Apple banana ORANGE Grape"
# 不使用 IGNORECASE
result = re.findall(r'apple', text)
print(result)  # []

# 使用 IGNORECASE
result = re.findall(r'apple', text, re.IGNORECASE)
print(result)  # ['Apple']

# 匹配所有水果名(忽略大小写)
fruits = re.findall(r'[a-z]+', text, re.I)
print(fruits)  # ['Apple', 'banana', 'ORANGE', 'Grape']
2.2 re.MULTILINE (re.M) - 多行模式

作用:改变 ^$ 的行为,使它们分别匹配每一行的开头和结尾

示例

text = """First line
Second line
Third line"""

# 不使用 MULTILINE
result = re.findall(r'^\w+', text)
print(result)  # ['First']

# 使用 MULTILINE
result = re.findall(r'^\w+', text, re.MULTILINE)
print(result)  # ['First', 'Second', 'Third']

# 匹配每行末尾的单词
result = re.findall(r'\w+$', text, re.M)
print(result)  # ['line', 'line', 'line']
2.3 re.DOTALL (re.S) - 点号匹配所有模式

作用:使 . 匹配包括换行符在内的所有字符

示例

text = """Start
Middle
End"""

# 不使用 DOTALL
result = re.findall(r'Start.*End', text)
print(result)  # []

# 使用 DOTALL
result = re.findall(r'Start.*End', text, re.DOTALL)
print(result)  # ['Start\nMiddle\nEnd']

# 提取多行注释内容
html = """<!-- 
这是多行
HTML注释 
-->"""
comment = re.findall(r'<!--(.*?)-->', html, re.DOTALL)
print(comment)  # [' \n这是多行\nHTML注释 \n']
2.4 re.VERBOSE (re.X) - 详细模式

作用:允许在正则表达式中添加空白和注释,使其更易读

示例

# 复杂的电话号码正则表达式
phone_re = re.compile(r'''
    ^(\+\d{1,3})?       # 国际区号
    [-\s]?              # 分隔符
    (\d{3})             # 前3位
    [-\s]?              # 分隔符
    (\d{3,4})           # 中间3或4位
    [-\s]?              # 分隔符
    (\d{4})             # 最后4位
    $''', re.VERBOSE)

text = "Phone numbers: +86-138-1234-5678, 010-87654321"
numbers = phone_re.findall(text)
print(numbers)  # [('+86', '138', '1234', '5678'), ('', '010', '8765', '4321')]
2.5 re.ASCII (re.A) - ASCII 模式

作用:使 \w, \W, \b, \B, \d, \D, \s, \S 只匹配 ASCII 字符

示例

text = "Python3 中文 Español café"

# 默认模式(Unicode)
result = re.findall(r'\w+', text)
print(result)  # ['Python3', '中文', 'Español', 'café']

# ASCII 模式
result = re.findall(r'\w+', text, re.ASCII)
print(result)  # ['Python3', 'Espa', 'ol', 'caf']
2.6 re.UNICODE (re.U) - Unicode 模式

作用:使 \w, \W, \b, \B, \d, \D, \s, \S 匹配 Unicode 字符(Python 3 默认)

示例

text = "Русский 中文 ελληνικά"

# 默认就是 UNICODE 模式
result = re.findall(r'\w+', text)
print(result)  # ['Русский', '中文', 'ελληνικά']

# 显式指定 UNICODE
result = re.findall(r'\w+', text, re.UNICODE)
print(result)  # ['Русский', '中文', 'ελληνικά']
2.7 re.LOCALE (re.L) - 区域设置模式

作用:使 \w, \W, \b, \B 依赖当前区域设置(不推荐使用)

示例

import locale

# 设置区域为德语
locale.setlocale(locale.LC_ALL, 'de_DE.UTF-8')

text = "straße café"
result = re.findall(r'\w+', text, re.LOCALE)
print(result)  # ['straße', 'café']

3. 组合使用多个 flags

可以通过按位或 (|) 操作符组合多个 flags

示例

text = """Name: John
AGE: 30
name: Jane
age: 25"""

# 同时使用 IGNORECASE 和 MULTILINE
results = re.findall(r'^name:\s*(\w+)', text, re.I | re.M)
print(results)  # ['John', 'Jane']

# 解析多行配置项
config = """[Server]
host = example.com
port = 8080
timeout = 30"""

settings = re.findall(
    r'^(\w+)\s*=\s*(.*)$', 
    config, 
    re.MULTILINE | re.VERBOSE
)
print(settings)  # [('host', 'example.com'), ('port', '8080'), ('timeout', '30')]

4. 实际应用场景

4.1 解析日志文件(多行模式)

log = """2023-04-15 10:00:00 [INFO] System started
2023-04-15 10:01:23 [ERROR] Database connection failed
2023-04-15 10:02:45 [WARN] Disk space low"""

# 提取所有错误日志(带时间戳)
errors = re.findall(
    r'^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) \[ERROR\] (.*)$',
    log,
    re.MULTILINE
)
print(errors)  # [('2023-04-15 10:01:23', 'Database connection failed')]
4.2 提取HTML内容(点号匹配所有)
html = """<div>
    <p>First paragraph</p>
    <p>Second paragraph</p>
</div>"""

# 提取所有段落内容
paragraphs = re.findall(
    r'<p>(.*?)</p>',
    html,
    re.DOTALL  # 使 . 匹配换行符
)
print(paragraphs)  # ['First paragraph', 'Second paragraph']
4.3 多语言文本处理(Unicode模式)
text = "English: hello, 中文: 你好, Français: bonjour"

# 提取所有非ASCII单词
words = re.findall(
    r'[^\x00-\x7F]+',  # 匹配非ASCII字符
    text,
    re.UNICODE
)
print(words)  # ['你好', 'bonjour']
4.4 复杂模式匹配(详细模式)
# 匹配各种格式的日期
date_re = re.compile(r'''
    ^
    (?:20\d{2}|19\d{2})  # 年份 1900-2099
    [-/.]                # 分隔符
    (?:0[1-9]|1[0-2])    # 月份 01-12
    [-/.]                # 分隔符
    (?:0[1-9]|[12][0-9]|3[01])  # 日 01-31
    $''', re.VERBOSE)

dates = ["2023-04-15", "1999/12/31", "2000.01.01"]
valid_dates = [d for d in dates if date_re.search(d)]
print(valid_dates)  # ['2023-04-15', '1999/12/31', '2000.01.01']

5. 注意事项

  1. flag 的作用范围:flags 会影响整个正则表达式的行为
  2. flag 的组合:多个 flags 可以组合使用,但要注意它们之间的交互
  3. 性能考虑:某些 flags(如 re.UNICODE)可能会影响性能
  4. 预编译正则表达式:频繁使用的正则表达式应该先编译再使用
    pattern = re.compile(r'your_pattern', flags=re.I | re.M)
    results = pattern.findall(text)
    
  5. Python 3 的默认行为:在 Python 3 中,re.UNICODE 是默认启用的

通过合理使用这些 flags,你可以编写出更强大、更灵活的正则表达式,适应各种复杂的文本处理需求。


网站公告

今日签到

点亮在社区的每一天
去签到