python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python 正则表达式 re.findall()

Python 正则表达式 re.findall()全面解析

作者:doris8204

本文详解Python re.findall()方法,用于提取字符串中所有正则匹配项,重点涵盖分组处理、flags参数(如忽略大小写、多行模式、Unicode支持等)及应用场景,如提取邮件、URL、日志信息等,并提醒注意性能与返回值格式差异,感兴趣的朋友跟随小编一起看看吧

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

基本语法

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

参数说明:

返回值:

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. 性能优化建议

预编译常用正则表达式:

pattern = re.compile(r'\d+')
numbers = pattern.findall(text)

尽量使用具体模式而非宽泛模式:

# 不好的写法
re.findall(r'.*:\s*(.*)', text)
# 更好的写法
re.findall(r'\w+:\s*(\w+)', text)

避免过度使用回溯:

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

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

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

1. 常用 flags 概览

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

2. 各 flag 详细说明及示例

2.1re.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.2re.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.3re.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.4re.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.5re.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.6re.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.7re.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,你可以编写出更强大、更灵活的正则表达式,适应各种复杂的文本处理需求。

到此这篇关于Python 正则表达式 re.findall()全面解析的文章就介绍到这了,更多相关Python 正则表达式 re.findall()内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文