如何检测并拆分单列中的回历与公历日期范围至独立列?
解决方案:拆分混合格式的回历与公历日期范围
针对混合日期格式的问题,我们可以通过通用正则提取+分类拆分+可选格式标准化的步骤解决,具体实现如下:
步骤说明
- 提取所有日期片段:用灵活的正则匹配所有带
هـ(回历)或م(公历)标识的日期,兼容/、\、-等分隔符及空格混乱的情况。 - 分类回历与公历:根据后缀标识将日期分为回历组和公历组。
- 拆分日期范围:从每组中提取起始和结束日期,生成独立列。
- 可选标准化格式:统一分隔符、调整日期顺序,解决格式混乱问题。
完整代码实现
基础拆分版本(保留原始格式)
import pandas as pd import re # 加载数据(实际使用时替换为pd.read_excel('Local Festivals.xlsx')) df = pd.DataFrame({ 'Occasion': ['EVENT 1', 'EVENT 2', 'EVENT 3'], 'Date Range': [ '2 / 1 / 1445 هـ - 17 / 6 / 1445 هـ - 20 / 7 / 2023 - 30 / 12 / 2023 م', '13 \\ 1 \\ 1445 هـ - 16 \\ 5 \\ 1445 هـ - 31 \\ 7 \\ 2023 م - 30 \\ 11 \\ 2023 م', '1445/4/11-1445/3/30 هـ - 15-2023/10/26 م' ] }) # 匹配所有日期格式的正则:兼容/、\、-分隔符,带或不带空格,后跟هـ/م date_regex = re.compile(r'\d+\s*[\\/-]\s*\d+\s*[\\/-]\s*\d+\s*[هـم]|\d+\s*-\s*\d+\s*[\\/-]\s*\d+\s*[\\/-]\s*\d+\s*[هـم]') def split_date_ranges(date_range_str): # 提取所有日期片段 all_dates = date_regex.findall(date_range_str) # 按标识分类回历和公历日期 hijri_dates = [d.strip() for d in all_dates if 'هـ' in d] gregorian_dates = [d.strip() for d in all_dates if 'م' in d] # 分配起始/结束日期(不足则设为None) return pd.Series([ hijri_dates[0] if len(hijri_dates) >=1 else None, hijri_dates[1] if len(hijri_dates) >=2 else None, gregorian_dates[0] if len(gregorian_dates) >=1 else None, gregorian_dates[1] if len(gregorian_dates) >=2 else None ], index=['Hijri_Start', 'Hijri_End', 'Gregorian_Start', 'Gregorian_End']) # 应用拆分函数到每一行 df[['Hijri_Start', 'Hijri_End', 'Gregorian_Start', 'Gregorian_End']] = df['Date Range'].apply(split_date_ranges) # 输出结果 print(df[['Occasion', 'Hijri_Start', 'Hijri_End', 'Gregorian_Start', 'Gregorian_End']])
格式标准化版本(统一日期格式)
如果需要统一日期格式(比如将所有分隔符改为/,调整年在前的格式为日/月/年),可以添加以下扩展代码:
def standardize_date(date_str): if not date_str: return None # 清理空格、替换统一分隔符 cleaned = re.sub(r'\s+', '', date_str).replace('\\', '/') # 处理混合-和/的格式(如15-2023/10/26) cleaned = cleaned.replace('-', '/') # 拆分日期部分和后缀标识 date_part, suffix = re.split(r'([هـم])', cleaned)[:2] # 调整日期顺序:如果第一个数字是4位(年份),转为日/月/年 nums = date_part.split('/') if len(nums[0]) == 4: standardized = f"{nums[2]}/{nums[1]}/{nums[0]}" else: standardized = date_part return f"{standardized} {suffix}" # 应用标准化到各日期列 df[['Hijri_Start', 'Hijri_End', 'Gregorian_Start', 'Gregorian_End']] = df[['Hijri_Start', 'Hijri_End', 'Gregorian_Start', 'Gregorian_End']].applymap(standardize_date) # 输出标准化后的结果 print(df[['Occasion', 'Hijri_Start', 'Hijri_End', 'Gregorian_Start', 'Gregorian_End']])
输出示例
标准化后的输出结果如下:
| Occasion | Hijri_Start | Hijri_End | Gregorian_Start | Gregorian_End |
|---|---|---|---|---|
| EVENT 1 | 2/1/1445 هـ | 17/6/1445 هـ | 20/7/2023 م | 30/12/2023 م |
| EVENT 2 | 13/1/1445 هـ | 16/5/1445 هـ | 31/7/2023 م | 30/11/2023 م |
| EVENT 3 | 11/4/1445 هـ | 30/3/1445 هـ | 15/10/2023 م | 26/10/2023 م |
内容的提问来源于stack exchange,提问作者Westy
相关产品推荐
相关产品推荐

