def regex(pattern, text, mode='search', flags=0, **kwargs):"""统一正则入口:mode驱动行为,内联标志优先,结果归一化为None/非None"""if not pattern: raise ValueError("pattern cannot be empty")if text is None: raise ValueError("text cannot be None") 内联标志透传,不预解析;显式flags仅补缺(与内联不冲突)import re mode_map = {'search': (re.search, re.IGNORECASE), 'findall': (re.findall, re.IGNORECASE), 'fullmatch': (re.fullmatch, re.IGNORECASE), 'split': (re.split, 0), 'sub': (re.sub, re.IGNORECASE), } if mode not in mode_map:raise ValueError(f"unsupported mode: {mode}") func, default_flags = mode_map[mode] effective_flags = flags | default_flags try:result = func(pattern, text, flags=effective_flags, **kwargs) # 归一化:findall空列表→None;sub/count/repl透传;其他原样返回 if mode == 'findall' and result == []: return None if mode == 'sub': return result

写一个支持多种正则匹配模式的通用函数,关键不是堆砌选项,而是把“模式切换”这件事封装清楚——让调用者只关心“我要干什么”,而不是“该传哪个标志、怎么编译正则对象”。
统一入口 + 模式枚举驱动行为
避免用一堆布尔参数(如 ignore_case=True, multiline=False, dotall=True)拼凑调用。改用一个 mode 参数,取值为预定义的字符串或枚举,比如:'search'、'findall'、'sub'、'split'、'fullmatch'。内部根据 mode 自动选择对应 re 函数,并统一处理标志(flags)。
- 标志不手动传,而是按 mode 默认启用合理组合:例如
'search'默认带re.IGNORECASE(可配置),'split'默认不开启re.DOTALL - 允许额外传入
flags覆盖默认值,但优先级明确:用户显式传的 > mode 默认的 - 这样调用简洁:
regex('hello', 'HeLLo world', mode='search'),不用记re.search(..., flags=re.I)
支持内联标志与动态模式切换
有些场景需要单次匹配就启用特定标志,比如临时忽略大小写或跨行匹配。可在 pattern 前加内联标志(如 (?i)hello),函数应原样透传给 re 模块——不做预解析、不强行合并 flags。同时提供快捷方式:
-
regex('(?i)hello', text, mode='search')—— 内联控制,完全自由 -
regex('hello', text, mode='search', ignore_case=True)—— 语义化开关,底层自动转成re.I - 两者互斥时(比如 pattern 里写了
(?i)又传了ignore_case=False),以 pattern 内联为准(re 模块本身行为)
结果标准化与错误防御
不同 mode 返回类型差异大(Match、list、str、list),函数应做轻量归一化:
- 所有成功匹配都返回非 None 值;失败统一返回
None(findall空列表也转为None,除非显式要求保留空列表) - 对
sub模式,支持count和repl参数,并允许repl是函数或字符串 - 捕获异常:
re.error直接抛出,带原始 pattern 提示;空 pattern 或 None 输入主动报错,不依赖底层失败
可扩展的模式注册机制(进阶)
如果后续要加自定义行为(比如“提取所有邮箱并去重”、“匹配后自动 URL 解码”),不要硬编码。预留 handlers 注册点:
- 定义
register_mode(name, func),func 接收pattern、text、**kwargs - 内置 mode(search/findall/sub等)也走同一注册表,保持逻辑一致
- 新业务模式可独立实现,不侵入主函数,例如:
register_mode('emails', extract_emails)











