You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

re.sub方法为何替换为捕获组名而非对应捕获值?

问题:Python re.sub处理日期字符串时捕获组未正确替换

需求说明

仅对未附带hh:mm am/pm时间标识的日期格式(如2022_-_02_-_18)进行改写,包裹为(日期 00:00 am)形式;已附带时间标识的日期保持原样不变。

原代码及问题

原测试代码尝试用re.sub结合捕获组和lambda函数处理,但替换时输出了\g<year>这类捕获组名称而非实际匹配值,且错误修改了带时间的日期:

import re, datetime

# example
input_text = "Alrededor de las 00:16 am o las 23:30 pm 2022_-_02_-_18 , quizas cerca del 2022_-_02_-_18 llega el avion, pero no a las (2022_-_02_-_18 00:16 am), de esos hay dos (22)"

# identification pattern
input_date_structure = r"(?P<year>\d*)_-_(?P<month>\d{2})_-_(?P<startDay>\d{2})"
identify_only_date_regex_00 = input_date_structure + r"[\s|]*" + r"(\d{2}:\d{2}[\s|]*[ap]m)?" # to identify if there is a time after the date
identify_only_date_regex_01 = r"(\d{2}:\d{2}[\s|]*[ap]m)?" + r"[\s|]*" + input_date_structure # to identify if there is a time before the date

# replacement structure
date_restructuring_structure = r"\g<year>_-_\g<month>_-_\g<startDay>"
restructuring_only_date = lambda x: x.group() if x.group(1) else " (" + date_restructuring_structure + " 00:00 am)"

# do the replace with re.sub() method and the regex patterns instructions
input_text = re.sub(identify_only_date_regex_00, restructuring_only_date, input_text)
input_text = re.sub(identify_only_date_regex_01, restructuring_only_date, input_text)

# print output
print(repr(input_text)) # --> output

错误输出

'Alrededor de las 00:16 am o las 23:30 pm 2022_-_02_-_18 , quizas cerca del (\\g<year>_-_\\g<month>_-_\\g<startDay> 00:00 am) llega el avion, pero no a las ( (\\g<year>_-_\\g<month>_-_\\g<startDay> 00:00 am) 00:16 am), de esos hay dos (22)'

期望输出

"Alrededor de las 00:16 am o las 23:30 pm 2022_-_02_-_18 , quizas cerca del (2022_-_02_-_18 00:00 am) llega el avion, pero no a las (2022_-_02_-_18 00:16 am), de esos hay dos (22)"

问题原因

  1. 捕获组语法使用错误:\g<year>这类语法仅在re.sub的第二个参数为字符串时会被解析为捕获组内容;但在lambda函数中,直接拼接该字符串只会把它当作普通文本输出,不会替换为实际匹配值。
  2. 正则逻辑缺陷:原正则会匹配带时间的日期(因为时间部分是可选分组),且两次替换会重复处理已修改的内容(比如把带时间的日期也错误包裹)。

修正方案

关键修改点

  • 用负向前后断言编写正则,确保仅匹配前后没有时间标识的独立日期,避免误匹配带时间的情况。
  • 在lambda函数中直接通过匹配对象的group()方法获取捕获组的实际值,而非使用\g<name>语法。
  • 排除已被括号包裹的日期,避免重复处理。

修正后的代码

import re

input_text = "Alrededor de las 00:16 am o las 23:30 pm 2022_-_02_-_18 , quizas cerca del 2022_-_02_-_18 llega el avion, pero no a las (2022_-_02_-_18 00:16 am), de esos hay dos (22)"

# 正则:匹配前后无时间、且未被括号包裹的独立日期
pattern = r"""
    (?<!\d{2}:\d{2}\s*[ap]m\s*)  # 前面没有hh:mm am/pm格式的时间
    (?<!\()                      # 前面没有左括号(避免匹配已包裹的日期)
    (?P<year>\d*)_-_(?P<month>\d{2})_-_(?P<startDay>\d{2})
    (?!\s*\d{2}:\d{2}\s*[ap]m)   # 后面没有hh:mm am/pm格式的时间
    (?!\))                       # 后面没有右括号
"""

def replace_date(match):
    # 获取实际捕获的日期各部分
    date_str = f"{match.group('year')}_-_{match.group('month')}_-_{match.group('startDay')}"
    return f"({date_str} 00:00 am)"

# 使用VERBOSE模式让正则更易读,同时执行替换
output_text = re.sub(pattern, replace_date, input_text, flags=re.VERBOSE)

print(repr(output_text))

输出结果

'Alrededor de las 00:16 am o las 23:30 pm 2022_-_02_-_18 , quizas cerca del (2022_-_02_-_18 00:00 am) llega el avion, pero no a las (2022_-_02_-_18 00:16 am), de esos hay dos (22)'

内容的提问来源于stack exchange,提问作者Matt095

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 04:50:44