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

如何仅对未被前后时间子串包围的日期字符串执行替换?

问题描述

需求:仅对未被hh:mm am/pm格式时间前后跟随的yyyy_-_mm_-_dd格式日期,替换为(日期 00:00 am);前后带有该格式时间的日期不替换。但现有正则实现错误修改了带前后时间的日期,导致输出不符合预期。

现有代码

import re, datetime

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 (2022_-_02_-_18 20:16 pm) a las (2022_-_02_-_18 00:16 am), de esos hay dos (22)"

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

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"(\b\d{2}:\d{2}[\s|]*[ap]m)?" #to identify if there is a time after  the date
identify_only_date_regex_01 = r"(\b\d{2}:\d{2}[\s|]*[ap]m)?" + r"[\s|]*" + input_date_structure #to identify if there is a time before the date

date_restructuring_structure = r"\g<year>_-_\g<month>_-_\g<startDay>"
restructuring_only_date = lambda x: x.group() if x.group(1) else "(" + fr"{x.expand(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(2022_-_02_-_18 00:00 am) llega el avion, pero no ((2022_-_02_-_18 00:00 am) 20:16 pm) a las ((2022_-_02_-_18 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 (2022_-_02_-_18 20:16 pm) a las (2022_-_02_-_18 00:16 am), de esos hay dos (22)"

规则示例

  • 不替换:"sdsdds 2022_-_02_-_18 00:16 am sdsddssd2"(日期后带时间)
  • 不替换:"sdsdsd 00:16 am 2022_-_02_-_18 sdsdsd"(日期前带时间)
  • 替换:"sdsdds 2022_-_02_-_18 sdsdsd"(孤立日期)

问题原因
  1. 正则逻辑反向:原正则用可选捕获组(...)?"尝试匹配时间,意味着即使存在前后时间,正则仍会忽略时间、单独匹配日期部分(可选组允许匹配为空),导致带时间的日期被错误替换。
  2. 两次替换重复干扰:先替换“日期后可能带时间”的场景,再替换“日期前可能带时间”的场景,第二次替换会错误匹配已处理的内容,比如把(2022_-_02_-_18 20:16 pm)中的日期单独揪出来替换。
  3. 未明确排除时间场景:原正则没有主动排除“日期前后存在有效时间”的情况,只是被动尝试匹配时间,无法精准定位孤立日期。

修正方案

使用负向断言(反向否定预查+正向否定预查)精准匹配孤立日期,确保日期前后不存在目标格式的时间,单次替换即可完成需求。

修正后代码

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 (2022_-_02_-_18 20:16 pm) a las (2022_-_02_-_18 00:16 am), de esos hay dos (22)"

# 定义日期结构:限定年份为4位数字,更符合yyyy格式
input_date_structure = r"(?P<year>\d{4})_-_(?P<month>\d{2})_-_(?P<startDay>\d{2})"
# 单独提取时间格式正则,便于维护
time_pattern = r"\b\d{2}:\d{2}\s*[ap]m\b"

# 核心正则:用负向断言排除前后带时间的日期
isolate_date_regex = re.compile(
    fr"(?<!{time_pattern}\s*){input_date_structure}(?!\s*{time_pattern})"
)

# 替换函数
def replace_isolate_date(match):
    date_str = match.group()
    return f"({date_str} 00:00 am)"

# 执行单次替换
output_text = isolate_date_regex.sub(replace_isolate_date, input_text)

print(repr(output_text))

修正说明

  1. 负向断言精准过滤:
    • (?<!{time_pattern}\s*):反向否定预查,确保日期前面没有“时间+任意空白”的内容,排除日期前带时间的场景。
    • (?!\s*{time_pattern}):正向否定预查,确保日期后面没有“任意空白+时间”的内容,排除日期后带时间的场景。
  2. 优化日期正则:将年份匹配从\d*改为\d{4},避免匹配非4位数字的无效年份。
  3. 单次替换避免干扰:一次匹配所有符合条件的孤立日期,不会重复处理导致错误。
  4. 模块化设计:将时间格式抽离为单独变量,后续修改时间格式只需调整一处。

内容的提问来源于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 05:35:19