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

Python实现UTF-8文本文件日期格式转换及代码调试求助

解决方案:转换文本文件中的日期格式(保留原内容)

一、Python 修正方案(解决你的代码问题)

首先,你的现有代码存在几个关键问题:

  • _repl 函数接收的是正则匹配对象(re.Match),不是字符串,所以不能直接用split("/")
  • while 循环完全多余,re.sub 会一次性处理当前行的所有匹配项
  • 不符合条件的匹配应该返回原匹配字符串,而不是x(你之前返回列表会导致格式错误)
  • 正则需要支持1-2位的日/月,同时要避免误匹配其他数字组合(比如123/45/2000这类无效格式)

修正后的完整代码

import re
import io

def _repl(match):
    # 从匹配对象中获取日、月、年的分组
    day = match.group(1)
    month = match.group(2)
    year = match.group(3)
    
    try:
        day_int = int(day)
        month_int = int(month)
        year_int = int(year)
        
        # 验证日期有效性和年份范围
        if (1 <= day_int <= 31) and (1 <= month_int <= 12) and (1970 <= year_int <= 2022):
            # 格式化为 yyyy-mm-dd,自动补前置零
            return f"{year_int:04d}-{month_int:02d}-{day_int:02d}"
        else:
            # 不符合条件,返回原日期字符串
            return match.group(0)
    except ValueError:
        # 转换失败(理论上正则已经确保是数字,这里是兜底)
        return match.group(0)

# 第一步:排查文件中是否存在日/月无前导零的日期
print("=== 排查无前导零的日期 ===")
with io.open("1.txt", mode="r", encoding="utf-8") as f:
    for line_num, line in enumerate(f, 1):
        # 匹配日或月是1位数字的日期
        matches = re.findall(r'\b(\d{1})/(\d{1,2})/(\d{4})\b|\b(\d{1,2})/(\d{1})/(\d{4})\b', line)
        for match in matches:
            # 提取有效匹配(排除空分组)
            date_parts = [part for part in match if part]
            if date_parts:
                print(f"第 {line_num} 行:{'/'.join(date_parts)}")

# 第二步:转换符合条件的日期
with io.open("1.txt", mode="r", encoding="utf-8") as f:
    content = f.read()

# 使用正则替换所有匹配的日期,确保匹配独立的日期(用\b单词边界避免误匹配)
converted_content = re.sub(r'\b(\d{1,2})/(\d{1,2})/(\d{4})\b', _repl, content)

with io.open('2.txt', mode='w', encoding="utf-8") as f:
    f.write(converted_content)

代码说明

  1. _repl 函数:接收匹配对象,提取日/月/年并验证范围,符合条件则格式化,否则返回原字符串
  2. 日期排查功能:提前扫描文件,找出所有日或月为1位数字的日期,方便你确认这类日期的存在
  3. 正则优化:用\b单词边界确保匹配的是独立的日期(比如不会匹配abc12/34/2000def中的部分)
  4. 异常处理:兜底处理数字转换失败的情况(虽然正则已经限制是数字,但增加鲁棒性)

二、Awk 解决方案(适合快速处理大文件)

如果你的文件很大,Awk 可能比 Python 更高效,以下是实现代码:

#!/usr/bin/awk -f

# 定义正则匹配 dd/mm/yyyy(支持1-2位日/月)
BEGIN {
    date_regex = /([0-9]{1,2})\/([0-9]{1,2})\/([0-9]{4})/
}

{
    line = $0
    # 循环匹配所有日期
    while (match(line, date_regex, parts)) {
        day = parts[1]
        month = parts[2]
        year = parts[3]
        
        # 验证日期有效性和年份范围
        if (day+0 >= 1 && day+0 <=31 && month+0 >=1 && month+0 <=12 && year+0 >=1970 && year+0 <=2022) {
            # 格式化日期,补前置零
            new_date = sprintf("%04d-%02d-%02d", year+0, month+0, day+0)
            # 替换当前匹配的日期
            sub(date_regex, new_date, line)
        } else {
            # 不符合条件,跳过替换(移动指针到匹配结束位置)
            line = substr(line, RSTART + RLENGTH)
        }
    }
    print line
}

使用方法

  1. 将上述代码保存为convert_dates.awk
  2. 运行命令:awk -f convert_dates.awk 1.txt > 2.txt
  3. 排查无前导零日期的命令:awk '/\b[0-9]{1}\/[0-9]{1,2}\/[0-9]{4}\b|\b[0-9]{1,2}\/[0-9]{1}\/[0-9]{4}\b/' 1.txt

三、关键注意事项

  • 日期有效性边界:代码中只做了基础的日(1-31)、月(1-12)验证,没有处理每个月的实际天数(比如2月最多29天),如果需要更严格的日期验证,可以引入datetime模块(Python)或Awk的日期处理函数
  • 避免误匹配:使用\b单词边界可以避免匹配像123/45/2000或12/345/2000这类无效格式,但如果日期前后有特殊字符(比如(12/3/2000)),可以调整正则为(?<![0-9])(\d{1,2})/(\d{1,2})/(\d{4})(?![0-9])(负向断言)
  • 编码保证:所有方案都默认处理UTF-8编码,确保你的输入文件确实是UTF-8格式

内容的提问来源于stack exchange,提问作者Uri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 20:32:41