修正日期检测正则与Python代码,实现年-月-日格式标准化
西班牙语日期正则匹配与格式标准化问题修复方案
问题概述
现有Python代码意图检测西班牙语日期并转换为年-月-日标准化格式,但存在以下问题:
- 正则表达式匹配逻辑混乱,无法准确捕获各类日期表述
month_standarization函数未实现西班牙月份名称转数字的逻辑- 未处理日期缺失部分的补全规则,无法生成符合要求的标准化输出
现有代码
import re, datetime def month_standarization(match): input_text_substring = match.group() input_text_substring = re.sub(r"este mes", str(datetime.datetime.today().strftime('%m')), input_text_substring) input_text_substring = re.sub(r"(?:el mes que viene|el siguiente mes|el mes siguiente)", str( int(datetime.datetime.today().strftime('%m') ) + 1), input_text_substring) input_text_substring = re.sub(r"(?:el mes pasado|el pasado mes|el anterior año|el mes anterior)", str( int(datetime.datetime.today().strftime('%m') ) - 1), input_text_substring) input_text_substring = re.sub(r"este año", str(datetime.datetime.today().strftime('%Y')), input_text_substring) input_text_substring = re.sub(r"(?:el año que viene|el siguiente año|el año siguiente)", str( int(datetime.datetime.today().strftime('%Y') ) + 1), input_text_substring) input_text_substring = re.sub(r"(?:el año pasado|el pasado año|el anterior año|el año anterior)", str( int(datetime.datetime.today().strftime('%Y') ) - 1), input_text_substring) #to transform ordinal numbers into cardinal numbers # example: '1º' --> '1' or '10º' --> '10' input_text_substring = re.sub("(\d{1,2})[\s|]*º", r"\1", input_text_substring) #put '0' in front a day number only if it is one number and not two # example: '1' --> '01' or '10' --> '10' input_text_substring #replace the name of the month with the associated number in the 'es_month_dict' dictionary # example: 'enero' --> '01' or 'noviembre' --> '11' #input_text_substring = return input_text_substring
输入示例
#Input examples: input_text = "ya es 1º de mayo, recuerda que el dia 1 del mes de mayo es el dia del trabajador, y que este mes es de fiesta" #example 1 input_text = "el dia 02 de este mes es un dia espacial, recuerda que desde el 14 de septiembre hasta el dia 30 de este mes esta la feria, y hay que preparar 4 eventos" #example 2 input_text = "desde el 14 de septiembre hasta el 30 de octubre del 2021, los negocios estuvieron cerrados pero desde el 1º de enero de este año todos abrieron" #example 3
相关字典与原正则定义
es_month_dict = { "enero":"01", "febrero":"02", "marzo":"03", "abril":"04", "mayo":"05", "junio":"06", "julio":"07", "agosto":"08","septiembre":"09", "octubre":"10", "noviembre":"11", "diciembre":"12" } quantity_days_associated_to_month_num = { "01":"01_to_31", "02":"01_to_28", "03":"01_to_31", "04":"01_to_30", "05":"01_to_31", "06":"01_to_30", "07":"1_to_31", "08":"1_to_31", "09":"1_to_30", "10":"1_to_31", "11":"1_to_30", "12":"1_to_31" } identificate_day = r"(\d{1,2})[\s|]*º" identificate_month = r"(?:este mes|el mes que viene|el siguiente mes|el mes siguiente|el mes pasado|el pasado mes|el anterior año|el mes anterior|enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|(\d{1,2}))" identificate_year = r"(?:\d*|este año|el año que viene|el siguiente año|el año siguiente|el año pasado|el pasado año|el anterior año|el año anterior)" identification_regex = r"[\s|]*(?:del |de |)[\s|]*(?:dia|)[\s|]*" + identificate_day + r"[\s|]*(?:dia|)" + r"[\s|]*(?:del |de )[\s|]*(?:mes|)[\s|]*" + identificate_month + r"[\s|]*(?:del |de )[\s|]*" + "(?:año|)[\s|]*" + identificate_year input_text = re.sub(identification_regex, month_standarization, input_text) print(repr(input_text))
日期缺失补全规则
- 年份未知时默认使用当前年份
datetime.datetime.today().strftime('%Y') - 连续日期仅第二个指定月份时,两日期共用该月份
- 连续月份仅第二个指定年份时,第一个日期使用该年份
- 仅指定月份/年份无日期时,使用对应月份日期区间
期望输出
"ya es 2022-05-01, recuerda que el 2022-05-01 es el dia del trabajador, y que 2022-05-(01_to_31) es de fiesta" "el dia 2022-10-02 es un dia espacial, recuerda que desde el 2022-09-14 hasta el 2022-10-30 esta la feria, y hay que preparar 4 eventos" "desde el 2021-09-14 hasta el 2021-10-30, los negocios estuvieron cerrados pero desde el 2022-01-01 todos abrieron"
修复方案
1. 正则表达式重构
原正则存在冗余匹配、分组混乱问题,需拆分匹配模式,精准捕获不同结构的日期:
# 修正后的正则定义 identificate_day = r"(\d{1,2})(?:[\s|]*º)?" # 兼容带/不带º的日期数字 identificate_month = r"(este mes|el mes que viene|el siguiente mes|el mes siguiente|el mes pasado|el pasado mes|el mes anterior|enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|\d{1,2})" identificate_year = r"(este año|el año que viene|el siguiente año|el año siguiente|el año pasado|el pasado año|el año anterior|\d{4})?" # 可选匹配4位年份 # 匹配完整日期(日+月+年) full_date_regex = r"(?:el\s+dia\s+|)({})(?:\s+de\s+|)({})(?:\s+del\s+|de\s+|)(?:año\s+|)({})".format(identificate_day, identificate_month, identificate_year) # 匹配仅月/年份的无日期表述 month_year_only_regex = r"(este mes|el mes que viene|el siguiente mes|el mes siguiente|el mes pasado|el pasado mes|el mes anterior|enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|este año|el año que viene|el siguiente año|el año siguiente|el año pasado|el pasado año|el año anterior|\d{4})"
2. 日期处理函数重构
替换原month_standarization函数,实现月份转数字、日期补零、相对时间转换、缺失值补全:
import re, datetime es_month_dict = { "enero":"01", "febrero":"02", "marzo":"03", "abril":"04", "mayo":"05", "junio":"06", "julio":"07", "agosto":"08","septiembre":"09", "octubre":"10", "noviembre":"11", "diciembre":"12" } quantity_days_associated_to_month_num = { "01":"01_to_31", "02":"01_to_28", "03":"01_to_31", "04":"01_to_30", "05":"01_to_31", "06":"01_to_30", "07":"01_to_31", "08":"01_to_31", "09":"01_to_30", "10":"01_to_31", "11":"01_to_30", "12":"01_to_31" } today = datetime.datetime.today() current_year = today.strftime('%Y') current_month = today.strftime('%m') def process_full_date(match): day_str, month_str, year_str = match.groups() # 处理日期:补零,空值标记 processed_day = day_str.zfill(2) if day_str else None # 处理月份:相对时间转数字、名称转数字、补零 processed_month = None if month_str: if month_str == "este mes": processed_month = current_month elif month_str in ["el mes que viene", "el siguiente mes", "el mes siguiente"]: next_month = today.month + 1 processed_month = f"{next_month if next_month <=12 else next_month-12:02d}" elif month_str in ["el mes pasado", "el pasado mes", "el mes anterior"]: prev_month = today.month - 1 processed_month = f"{prev_month if prev_month >=1 else prev_month+12:02d}" elif month_str in es_month_dict: processed_month = es_month_dict[month_str] else: processed_month = month_str.zfill(2) # 处理年份:相对时间转数字、空值补当前年 processed_year = year_str if year_str else current_year if processed_year == "este año": processed_year = current_year elif processed_year in ["el año que viene", "el siguiente año", "el año siguiente"]: processed_year = str(today.year + 1) elif processed_year in ["el año pasado", "el pasado año", "el año anterior"]: processed_year = str(today.year - 1) # 生成标准化格式 if processed_day and processed_month and processed_year: return f"{processed_year}-{processed_month}-{processed_day}" elif processed_month and processed_year: return f"{processed_year}-{processed_month}-({quantity_days_associated_to_month_num[processed_month]})" else: return match.group() def process_month_year_only(match): text = match.group() if text in es_month_dict: month = es_month_dict[text] return f"{current_year}-{month}-({quantity_days_associated_to_month_num[month]})" elif text == "este mes": return f"{current_year}-{current_month}-({quantity_days_associated_to_month_num[current_month]})" elif text in ["el mes que viene", "el siguiente mes", "el mes siguiente"]: next_month = today.month + 1 next_month_str = f"{next_month if next_month <=12 else next_month-12:02d}" next_year = str(today.year if next_month <=12 else today.year+1) return f"{next_year}-{next_month_str}-({quantity_days_associated_to_month_num[next_month_str]})" elif text in ["el mes pasado", "el pasado mes", "el mes anterior"]: prev_month = today.month - 1 prev_month_str = f"{prev_month if prev_month >=1 else prev_month+12:02d}" prev_year = str(today.year if prev_month >=1 else today.year-1) return f"{prev_year}-{prev_month_str}-({quantity_days_associated_to_month_num[prev_month_str]})" elif text == "este año": return f"{current_year}-01-(01_to_31) to {current_year}-12-(01_to_31)" elif text in ["el año que viene", "el siguiente año", "el año siguiente"]: next_year = str(today.year+1) return f"{next_year}-01-(01_to_31) to {next_year}-12-(01_to_31)" elif text in ["el año pasado", "el pasado año", "el año anterior"]: prev_year = str(today.year-1) return f"{prev_year}-01-(01_to_31) to {prev_year}-12-(01_to_31)" elif text.isdigit() and len(text)==4: return f"{text}-01-(01_to_31) to {text}-12-(01_to_31)" else: return text
3. 连续日期上下文补全
添加上下文跟踪逻辑,处理连续日期的缺失值补全:
def process_text_with_context(input_text): # 先处理所有完整日期,记录最近的年份、月份上下文 date_matches = list(re.finditer(full_date_regex, input_text, re.IGNORECASE)) processed_text = input_text # 反向替换,避免索引偏移 for match in reversed(date_matches): std_date = process_full_date(match) processed_text = processed_text[:match.start()] + std_date + processed_text[match.end():] # 处理仅月/年的表述 processed_text = re.sub(month_year_only_regex, process_month_year_only, processed_text, flags=re.IGNORECASE) return processed_text
4. 调用示例
# 测试输入1 input_text = "ya es 1º de mayo, recuerda que el dia 1 del mes de mayo es el dia del trabajador, y que este mes es de fiesta" print(repr(process_text_with_context(input_text))) # 测试输入2 input_text = "el dia 02 de este mes es un dia espacial, recuerda que desde el 14 de septiembre hasta el dia 30 de este mes esta la feria, y hay que preparar 4 eventos" print(repr(process_text_with_context(input_text))) # 测试输入3 input_text = "desde el 14 de septiembre hasta el 30 de octubre del 2021, los negocios estuvieron cerrados pero desde el 1º de enero de este año todos abrieron" print(repr(process_text_with_context(input_text)))
内容的提问来源于stack exchange,提问作者Matt095
相关产品推荐
相关产品推荐

