如何处理路径中重复日期格式码的文件匹配与日期提取问题
匹配含重复日期格式码的文件路径并提取日期
问题背景
需要识别所有路径匹配指定日期格式(例如%Y/%j/data_%d.txt)的文件,并提取关联日期。使用strptime是常规方案,但当格式中重复出现日期格式码(如%Y/%j/data_%Y%m%d.txt)时,strptime会因底层正则限制无法正常工作,该问题已在CPython仓库中记录。
原有递归实现(处理跨层级日期格式码)
此前我用一段递归代码处理日期格式码分布在不同目录层级的情况:
import os import datetime def get_path(path_format: list[str], path: str = "") -> list[str]: """返回所有匹配指定含日期格式路径规则的文件路径 :param path_format: 待遍历的路径规则列表,例如 ['test', '%Y', '%Y%m', 'data_%Y%m%d.txt'] :param path: 当前遍历的目录路径 :return: 所有匹配的文件路径列表 """ if len(path_format) == 0: return [path] current_format = path_format[0] if '%' in current_format: out = [] current_content = os.listdir(path) for content in current_content: try: datetime.datetime.strptime(content, current_format) except ValueError: continue out += get_path(path_format[1:], os.path.join(path, content)) return out else: path = os.path.join(path, current_format) if os.path.exists(path): return get_path(path_format[1:], path) else: return []
对应的目录结构示例:
$ tree data/2017/ data/2017/ ├── 001 │ └── data_20170101.txt └── 100 └── data_20170407.txt
调用示例:
>>> p = 'data/%Y/%j/data_%Y%m%d.txt' >>> p = p.split('/') >>> get_path(p) ['data/2017/100/data_20170407.txt', 'data/2017/001/data_20170101.txt']
新需求:处理同一目录/文件名内的重复日期格式码
现在需要处理日期格式码在同一目录或文件名中重复出现的场景,例如路径格式data/%Y/%j/data_%Y%m%dT0000_%Y%m%dT9000.txt。
临时解决方案(基于分隔符拆分处理)
周末我找到一种临时方案,虽不够理想但可满足需求:通过指定分隔符(如_)拆分目录名或文件名,分别解析各部分的日期信息后再合并,代码如下:
import os import datetime def merge_two_dates(d1, d2): return d1.replace(year=max(d1.year, d2.year), month=max(d1.month, d2.month), day=max(d1.day, d2.day), hour=max(d1.hour, d2.hour), minute=max(d1.minute, d2.minute), second=max(d1.second, d2.second), microsecond=max(d1.microsecond, d2.microsecond)) def merge_dates(dates): date = datetime.datetime.min for d in dates: date = merge_two_dates(date, d) return date def dates_from_path_rec(path_format: list[str], split_c: str = "", path: str = "") -> list[datetime.datetime]: """返回所有匹配指定含日期格式路径规则的文件对应的日期 :param path_format: 待遍历的路径规则列表,例如 ['test', '%Y', '%Y%m', 'data_%Y%m%d.txt'] :param split_c: 当同一目录/文件名内包含多个日期格式时,用于拆分的分隔符 :param path: 当前遍历的目录路径 :return: 所有匹配文件对应的日期列表 """ if len(path_format) == 0: return [datetime.datetime.min] current_format = path_format[0] if '%' in current_format: split_format = current_format.split(split_c) if len(split_c) > 0 else [current_format] out = [] current_content = os.listdir(path) for content in current_content: split_content = content.split(split_c) if len(split_c) > 0 else [content] if len(split_format) != len(split_content): continue try: dates = [datetime.datetime.strptime(sc, sf) for sc, sf in zip(split_content, split_format) if '%' in sf] except ValueError: continue date = merge_dates(dates) if date.strftime(current_format) != content: continue out += [merge_two_dates(date, d) for d in dates_from_path_rec(path_format[1:], split_c, os.path.join(path, content))] return out else: path = os.path.join(path, current_format) if os.path.exists(path): return dates_from_path_rec(path_format[1:], split_c, path) else: return []
内容的提问来源于stack exchange,提问作者Alexandre Novius
相关产品推荐
相关产品推荐

