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)
代码说明
_repl函数:接收匹配对象,提取日/月/年并验证范围,符合条件则格式化,否则返回原字符串- 日期排查功能:提前扫描文件,找出所有日或月为1位数字的日期,方便你确认这类日期的存在
- 正则优化:用
\b单词边界确保匹配的是独立的日期(比如不会匹配abc12/34/2000def中的部分) - 异常处理:兜底处理数字转换失败的情况(虽然正则已经限制是数字,但增加鲁棒性)
二、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 }
使用方法
- 将上述代码保存为
convert_dates.awk - 运行命令:
awk -f convert_dates.awk 1.txt > 2.txt - 排查无前导零日期的命令:
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
相关产品推荐
相关产品推荐

