如何仅在捕获组间含;或.\n时使用re.sub()执行替换?
问题需求
仅当**日期格式(\d{4}-\d{2}-\d{2})与指定时间短语(含pasado|despues|tras + 数字 + dias|dia及变体)**这两个捕获组之间存在至少一个;或.\n时,才使用Python的re.sub()执行替换操作。
现有代码
import re, datetime # 需要执行替换的示例输入 input_text = "Decian muchas cosas; Seguro eso ocurrira despues de 3 dias" input_text = "seguro eso ocurrira despues de 3 dias.\n empieza el 2021-11-12" input_text = "Recien el 2021-10-12; seguro eso ocurrira despues de 3 dias." # 不需要执行替换的示例输入 input_text = "seguro eso ocurrira despues de 3 dias. empieza el 2021-11-12" input_text = "Recien el 2021-10-12, seguro eso ocurrira despues 3 dias." # 日期加减函数 def add_or_subtract_days(datestr, days, operation): today = datetime.date.today() if operation == "add" : x = (datetime.datetime.strptime(str(today), "%Y-%m-%d") + datetime.timedelta(days=int(days))).strftime('%Y-%m-%d') elif operation == "subtract" : x = (datetime.datetime.strptime(str(today), "%Y-%m-%d") - datetime.timedelta(days=int(days))).strftime('%Y-%m-%d') return x some_text = r"[\s|]*" input_text = re.sub(r"(?:([12]\d{3}-[01]\d-[0-3]\d)(\D*?)|)" + some_text + r"(?:(?:pasados|pasado|despues del|despues de el|despues de|despues|tras) (\d+) (?:días|día|dias|dia)|(\d+) (?:días|día|dias|dia) (?:pasados|pasado|despues del|despues de el|despues de|despues|tras))" + some_text + r"(?:([12]\d{3}-[01]\d-[0-3]\d)(\D*?)|)", lambda m: print(m[3]) , #lambda m: add_or_subtract_days( m[1] or m[4] , m[2] or m[3] , "add" ), input_text) print("output: " + repr(input_text)) # 输出结果
期望输出(当前日期为2022-12-13时)
"Decian muchas cosas; Seguro eso ocurrira 2022-12-16" "seguro eso ocurrira 2022-12-16.\n empieza el 2021-11-12" "Recien el 2021-10-12; seguro eso ocurrira despues de 2022-12-16." 以下两个示例不执行替换,因为捕获组之间没有;或.\n "seguro eso ocurrira despues de 3 dias. empieza el 2021-11-12" "Recien el 2021-10-12, seguro eso ocurrira despues de 3 dias."
修正后的代码
import re, datetime def add_or_subtract_days(days, operation): # 固定当前日期为示例中的2022-12-13,实际使用可替换为datetime.date.today() today = datetime.date(2022, 12, 13) if operation == "add": return (today + datetime.timedelta(days=int(days))).strftime('%Y-%m-%d') elif operation == "subtract": return (today - datetime.timedelta(days=int(days))).strftime('%Y-%m-%d') def replace_matches(match): # 获取匹配到的天数 days = match.group(2) or match.group(5) if not days: return match.group(0) # 计算目标日期 target_date = add_or_subtract_days(days, "add") # 根据匹配的模式替换对应的短语部分 if match.group(1): # 日期在前,短语在后的情况,保留日期和分隔符,替换短语为目标日期 return f"{match.group(1)}{match.group(3)}{target_date}" else: # 短语在前,日期在后的情况,替换短语为目标日期,保留分隔符和后面的内容 return f"{match.group(4)}{target_date}{match.group(6)}" # 测试所有示例输入 test_cases = [ "Decian muchas cosas; Seguro eso ocurrira despues de 3 dias", "seguro eso ocurrira despues de 3 dias.\n empieza el 2021-11-12", "Recien el 2021-10-12; seguro eso ocurrira despues de 3 dias.", # 不需要替换的示例 "seguro eso ocurrira despues de 3 dias. empieza el 2021-11-12", "Recien el 2021-10-12, seguro eso ocurrira despues 3 dias." ] # 正则表达式:匹配两种情况,且日期和短语之间必须包含;或.\n pattern = r""" # 情况1:日期在前,短语在后,中间有;或.\n (([12]\d{3}-[01]\d-[0-3]\d)) (.*?(?:;|\.\n).*?) ((?:pasados|pasado|despues del|despues de el|despues de|despues|tras) (\d+) (?:días|día|dias|dia)) | # 情况2:短语在前,日期在后,中间有;或.\n ((?:pasados|pasado|despues del|despues de el|despues de|despues|tras) (\d+) (?:días|día|dias|dia)) (.*?(?:;|\.\n).*?) (([12]\d{3}-[01]\d-[0-3]\d)) """ for text in test_cases: result = re.sub(pattern, replace_matches, text, flags=re.VERBOSE) print(repr(result))
关键修改说明
正则表达式优化:
- 拆分两种匹配场景:日期在前短语在后、短语在前日期在后
- 强制要求两者之间的内容包含
;或.\n,用(.*?(?:;|\.\n).*?)捕获分隔部分 - 使用
re.VERBOSE模式提升正则可读性
日期函数修复:
- 修正原代码中
strptime的参数错误(date对象需转为字符串) - 示例中固定为2022-12-13方便验证,实际使用可替换为
datetime.date.today()
- 修正原代码中
替换逻辑优化:
- 自定义替换函数
replace_matches,根据不同匹配场景精准替换目标短语为计算后的日期 - 保留原文本中的分隔符和其他内容,确保替换后文本结构不变
- 自定义替换函数
内容的提问来源于stack exchange,提问作者Matt095
相关产品推荐
相关产品推荐

