Python生态正则表达式库:Re、Regex、Lark、Parsimonious、PRegEx、sre_yield、rstr、pygrok
本文汇总介绍几款Python生态下的正则表达式引擎(类库),并辅以入门实战案例。
| 库名 | 主要特点 | 性能 | 学习曲线 | 适用场景 | 活跃度 |
|---|---|---|---|---|---|
| re | 标准库,基础功能 | 良好 | 低 | 日常使用,简单模式 | 极高 |
| regex | 增强功能,Unicode | 优秀 | 中 | 高级功能,Unicode处理 | 高 |
| sre_yield | 模式生成 | 中等 | 中 | 测试数据生成 | 中 |
| pregex | 可读性,OO API | 良好 | 中 | 可维护代码,团队项目 | 中 |
| rstr | 随机生成 | 良好 | 低 | 测试数据,模拟 | 中 |
| parsimonious | PEG解析 | 中等 | 高 | 复杂解析,语法树 | 中 |
| lark | 现代解析 | 优秀 | 高 | 语言解析,编译器 | 高 |
Re
Python内置的正则表达式标准库,最基础、最广泛使用的正则工具。自1.5版本自带re模块,提供Perl风格的正则表达式模式。
核心特性:
- 内置支持:无需安装,Python标准库的一部分
- 基本功能:支持大多数正则表达式语法
- Unicode支持:完全支持Unicode字符
- 线程安全:在多线程环境中安全使用
性能特点:
- 编译后模式可重复使用
- 支持预编译优化
- 对于简单模式性能良好
适用场景:
- 日常文本处理任务
- 简单的模式匹配和替换
- 需要标准库依赖的项目
- 教学和学习目的
import re
# 基本匹配
pattern = re.compile(r'\d{3}-\d{3}-\d{4}')
match = pattern.search('Phone: 123-456-7890')
# 查找所有匹配
numbers = re.findall(r'\d+', 'a1b22c333')
# 替换
text = re.sub(r'\s+', ' ', 'too many spaces')
# 分割
parts = re.split(r'[,;]', 'a,b;c')
解读:
- compile函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象;
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;re.search匹配整个字符串,直到找到一个匹配。
Regex
re模块的增强替代品,完全兼容re模块,功能更多更强大,Unicode支持更好,性能更快。
核心增强:
- Unicode属性:完整的Unicode字符属性支持
- 递归模式:支持递归正则表达式
- 模糊匹配:支持模糊/近似匹配
- 命名组操作:更方便的命名组处理
- 原子分组:支持原子分组和占有量词
支持模糊匹配,可设置最大错误次数;处理嵌套字符集,在re里写[[a-z]--[aeiou]]会出问题,但regex里可优雅地表示所有辅音字母。支持完整的Unicode 17.0.0标准,\p{Horiz_Space}匹配水平空白字符。
两种工作模式:版本0完全兼容re模块行为,版本1则开启高级特性(如默认使用“完整大小写折叠”处理Unicode)。
可通过VERSION1标志切换,或在正则开头加(?V1)。全局开启新特性,设置regex.DEFAULT_VERSION = regex.VERSION1。
性能特点:
- 对于复杂模式通常比re更快
- 内存使用更优化
- 支持并行匹配(实验性)
适用场景:
- 需要高级正则功能
- Unicode文本处理
- 模糊搜索需求
- 复杂模式匹配
实战
安装:pip install regex
示例:
import regex
# 完全兼容re
import regex as re
# 模糊匹配,允许最多2处错误
regex.search(r'(?:test){e<=2}', 'tast')
# Unicode属性匹配
regex.search(r'\p{Script=Han}+', '中文测试')
# 递归模式
pattern = regex.compile(r'$ (?: [^()]+ | (?R) )* $', regex.VERBOSE)
# 命名组更方便的操作
match = regex.match(r'(?P<year>\d{4})-(?P<month>\d{2})', '2023-06')
year = match.group('year')
Lark
开源(GitHub,5.9K Star,485 Fork)专为Python设计的现代解析工具包,旨在提供高效、灵活且模块化的解析解决方案。它支持解析所有上下文无关语言(Context Free Grammars),适用于编程语言、自然语言以及数据格式的解析。
提供多种解析算法,包括Earley和LALR(1),支持EBNF语法、正则表达式。能自动生成带注释的解析树(AST),无需额外的构建代码。支持Unicode和自动行列跟踪,适合处理复杂语法和多语言场景。
解析fruit flies like bananas示例
核心特性:
- 多种解析算法支持:内置三种不同的解析算法:Earley(能解析任何上下文无关文法)、LALR(1)(性能最优)和CYK(较少使用)。用户可根据需求选择合适的算法平衡性能和表现力
- 先进的语法定义:基于EBNF(扩展巴科斯范式)的语法定义,支持多种便捷的符号表示法。例如,
item*表示零次或多次重复,item+表示一次或多次,item?表示可选项,使得语法定义更加直观 - 自动树构建:Lark会根据你定义的语法自动构建解析树,无需手工编写复杂的回调逻辑。这棵树是有注解的、结构化的,能直观地反映输入文本的语法结构
- 高效的词法分析:内置快速Unicode词法器,支持正则表达式,具有自动行计数功能,可直接用于错误报告和调试
- 灵活的Transformer和Visitor:提供两种遍历和转换解析树的方式,能轻松地从原始的解析树生成最终的数据结构或执行结果
适用场景:
- 复杂语言解析
- 需要词法分析
- 语法高亮实现
- 代码分析工具
安装:pip install lark
典型工作流程:
- 收集或创建输入示例:准备展示你的语言关键特性和行为的输入样本。这些样本应该覆盖你想要支持的各种语法构造
- 编写语法规则:用EBNF格式定义你的语言语法。语法应该是直观的,尽可能模拟你向其他人解释这个语言的方式
- 创建解析器实例:使用定义好的语法初始化Lark解析器,选择合适的解析算法
- 解析输入文本:使用解析器处理输入文本,得到结构化的解析树
- 转换和评估:使用Transformer或Visitor遍历解析树,将其转换为更符合业务需求的数据结构,或直接执行相关计算
经典的计算器示例:
from lark import Lark, Transformer, v_args
# 定义语法
CALC_GRAMMAR = """
?start: sum
?sum: product
| sum "+" product -> add
| sum "-" product -> sub
?product: atom
| product "*" atom -> mul
| product "/" atom -> div
?atom: NUMBER -> number
| "-" atom -> neg
| "(" sum ")"
%import common.NUMBER
%import common.WS
%ignore WS
"""
# 定义转换器来计算表达式
@v_args(inline=True)
class CalcTransformer(Transformer):
def number(self, token):
return float(token)
def add(self, a, b):
return a + b
def sub(self, a, b):
return a - b
def mul(self, a, b):
return a * b
def div(self, a, b):
return a / b
def neg(self, a):
return -a
# 创建解析器
parser = Lark(CALC_GRAMMAR, transformer=CalcTransformer())
# 使用示例
result = parser.parse("2 + 3 * 4")
print(f"2 + 3 * 4 = {result}") # 输出: 2 + 3 * 4 = 14.0
result = parser.parse("(2 + 3) * 4")
print(f"(2 + 3) * 4 = {result}") # 输出: (2 + 3) * 4 = 20.0
高级功能
- Lark实现SPPF(Shared Packed Parse Forest),一种处理歧义文法的高效方式。当语法存在多种解析方式时,SPPF能够在保持内存效率的前提下,存储所有可能的解析树
- 支持文法的模块化,可在一个文法中导入其他文法的终端和规则,实现代码复用
# grammar_base.lark
LETTER: "a".."z" | "A".."Z"
DIGIT: "0".."9"
# grammar_main.lark
%import grammar_base.LETTER
%import grammar_base.DIGIT
identifier: LETTER (LETTER | DIGIT)*
Parsimonious
开源(GitHub,1.9K Star,135 Fork)PEG(parsing expression grammars)解析器,但提供类似正则的语法解析能力。
核心特性:
- PEG语法:解析表达式文法
- 更好的错误恢复:更智能的错误处理
- 语法树生成:生成完整的语法树
适用场景:
- 复杂文本解析
- 编程语言解析
- 配置文件解析
- 需要语法树的场景
安装:pip install parsimonious
示例:
from parsimonious.grammar import Grammar
grammar = Grammar("""
expression = term (("+" / "-") term)*
term = factor (("*" / "/") factor)*
factor = number / ("(" expression ")")
number = ~r"\d+"
""")
tree = grammar.parse("1+2*(3+4)")
PRegEx
开源(GitHub,858 Star,25 Fork)通过Python类和方法构建正则表达式,提高可读性。官方文档。
核心特性:
- 面向对象API:使用类和方法构建模式
- 更好的可读性:代码即文档
- 类型提示:支持现代Python类型提示
适用场景:
- 需要高可读性的正则表达式
- 复杂模式的构建
- 团队协作项目
- 维护性要求高的代码
安装:pip install pregex
示例:
from pregex.core.classes import AnyLetter, AnyDigit, AnyFrom
from pregex.core.quantifiers import OneOrMore, Optional
from pregex.core.operators import Either
# 构建模式
username = OneOrMore(AnyLetter() | AnyDigit() | AnyFrom('._'))
domain = OneOrMore(AnyLetter() | AnyDigit() | AnyFrom('.-'))
tld = OneOrMore(AnyLetter())
email_pattern = username + '@' + domain + '.' + tld
# 编译和使用
pattern = email_pattern.get_pattern()
sre_yield
Google开源(GitHub,189 Star,45 Fork),已于26年1月22日归档,新的代码库在sre-yield,不过也没提交记录。
定位:从正则表达式生成所有可能匹配的字符串。
核心特性:
- 模式生成:根据正则表达式生成匹配字符串
- 有限生成:对于无限模式可设置限制
- 可迭代接口:支持迭代器模式
适用场景:
- 测试用例生成
- 密码爆破(合法场景)
- 语法测试
- 数据生成
安装:pip install sre_yield
示例:
from sre_yield import AllStrings
# 生成所有匹配字符串
for s in AllStrings('[ab]{2}'):
print(s) # aa, ab, ba, bb
# 设置长度限制
for s in AllStrings('a*', max_count=3):
print(s) # '', 'a', 'aa', 'aaa'
# 生成特定范围的匹配
for s in AllStrings('a{2,4}'):
print(s) # aa, aaa, aaaa
rstr
开源(GitHub,98 Star,20 Fork)基于正则表达式随机字符串生成。
核心特性:
- 随机生成:根据模式生成随机匹配
- 权重控制:可控制不同部分的生成概率
- 自定义字母表:支持自定义字符集
适用场景:
- 测试数据生成
- 模拟数据创建
- 性能测试
- 演示和示例
安装:pip install rstr
示例:
import rstr
# 生成随机匹配
rstr.xeger(r'[A-Z][a-z]{2,5}') # 如:'Abcde'
# 生成多个
rstr.xeger(r'\d{3}-\d{2}-\d{4}', 5) # 生成5个SSN格式字符串
# 使用自定义生成器
from rstr import Rstr
r = Rstr()
r.xeger(r'[a-z]{3}')
pygrok
Logstash中Grok过滤器的开源(GitHub,284 Star,74 Fork)Python版本。
实战
示例:
from pygrok import Grok
log_entry = '192.168.1.100 - admin [18/Jan/2025:15:45:11 +0800] "GET /api/user HTTP/1.1" 200 1234'
# 内置通用Apache日志解析模式
grok = Grok('%{COMMONAPACHELOG}')
result = grok.match(log_entry)
print("解析结果:", result)
# 解析结果: {'client': '192.168.1.100', 'ident': '-', 'auth': 'admin', 'timestamp': '18/Jan/2025:15:45:11 +0800', 'verb': 'GET', 'request': '/api/user', 'httpversion': '1.1', 'rawrequest': 'GET /api/user HTTP/1.1', 'response': '200', 'bytes': '1234'}
pattern = '%{WORD:name} is %{NUMBER:age:int} years old, weight %{NUMBER:weight:float} kg'
text = 'Alex is 25 years old, weight 70.5 kg'
grok = Grok(pattern)
match_data = grok.match(text)
print(f"姓名: {match_data['name']}, 明年年龄: {match_data['age'] + 1}")
相比于原生re模块,优势是内置上百种常见正则模板,极大降低代码维护成本和编写门槛。
缺点:多一步模式匹配的损耗,性能比纯手写的re稍慢一点点。
使用建议:
- 在脚本工具、爬虫清洗、普通的日志分析中无脑用pygrok提升效率;
- 只有在极端高并发的核心计算场景下,再考虑回滚到原生正则。
参考
更多推荐

所有评论(0)