新增blog

This commit is contained in:
2026-02-05 14:32:29 +08:00
parent 1f3e37fed1
commit ee576ac0db

View File

@@ -0,0 +1,270 @@
---
title: 编程日记
published: 2026-02-05
pinned: false
description: 编程过程中遇到的小细节
tags: [Note]
category: 学习日志
draft: false
---
# xlsx表格读取
当使用pandas读取xlsx表格时如果表格中有日期格式的数据读取时会看到日期被读取为数字如44000。如何才能读取到原本显示的日期格式
解决方案:
[扩展 openpyxl 对 Excel 中自定义单元格格式的处理 ](https://www.cnblogs.com/dyfblog/p/16339375.html)
openpyxl.styles.numbers.py中有一组格式
```python
BUILTIN_FORMATS = {
0: 'General',
1: '0',
2: '0.00',
3: '#,##0',
4: '#,##0.00',
5: '"$"#,##0_);("$"#,##0)',
6: '"$"#,##0_);[Red]("$"#,##0)',
7: '"$"#,##0.00_);("$"#,##0.00)',
8: '"$"#,##0.00_);[Red]("$"#,##0.00)',
9: '0%',
10: '0.00%',
11: '0.00E+00',
12: '# ?/?',
13: '# ??/??',
14: 'mm-dd-yy',
15: 'd-mmm-yy',
16: 'd-mmm',
17: 'mmm-yy',
18: 'h:mm AM/PM',
19: 'h:mm:ss AM/PM',
20: 'h:mm',
21: 'h:mm:ss',
22: 'm/d/yy h:mm',
37: '#,##0_);(#,##0)',
38: '#,##0_);[Red](#,##0)',
39: '#,##0.00_);(#,##0.00)',
40: '#,##0.00_);[Red](#,##0.00)',
41: r'_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)',
42: r'_("$"* #,##0_);_("$"* \(#,##0\);_("$"* "-"_);_(@_)',
43: r'_(* #,##0.00_);_(* \(#,##0.00\);_(* "-"??_);_(@_)',
44: r'_("$"* #,##0.00_)_("$"* \(#,##0.00\)_("$"* "-"??_)_(@_)',
45: 'mm:ss',
46: '[h]:mm:ss',
47: 'mmss.0',
48: '##0.0E+0',
49: '@',
}
```
从文档中找到中文对应的格式 ID 和格式字符串的对应关系,然后采用 hook 的方式将其注入 openpyxl 模块中即可。(注意这些代码需要在导入 openpyxl 模块之前执行)
```python
# 扩展openpyxl的数字格式
# 此处扩展的是中文格式
extra_formats = {
27: 'yyyy""m""',
28: 'm""d""',
29: 'm""d""',
30: "m-d-yy",
31: 'yyyy""m""d""',
32: 'h""mm""',
33: 'h""mm""ss""',
34: '上午/下午h""mm""',
35: '上午/下午h""mm""ss""',
36: 'yyyy""m""',
#
50: 'yyyy""m""',
51: 'm""d""',
52: 'yyyy""m""',
53: 'm""d""',
54: 'm""d""',
55: '上午/下午h""mm""',
56: '上午/下午h""mm""ss""',
57: 'yyyy""m""',
58: 'm""d""',
}
from openpyxl.styles.numbers import BUILTIN_FORMATS
BUILTIN_FORMATS.update(extra_formats)
```
示例代码:
```python
"""
使用扩展的中文数字格式读取Excel文件
扩展openpyxl的数字格式以支持中文日期时间格式
"""
from openpyxl import load_workbook
from openpyxl.styles.numbers import BUILTIN_FORMATS
import os
# 扩展openpyxl的数字格式
# 此处扩展的是中文格式
extra_formats = {
27: 'yyyy""m""',
28: 'm""d""',
29: 'm""d""',
30: "m-d-yy",
31: 'yyyy""m""d""',
32: 'h""mm""',
33: 'h""mm""ss""',
34: '上午/下午h""mm""',
35: '上午/下午h""mm""ss""',
36: 'yyyy""m""',
#
50: 'yyyy""m""',
51: 'm""d""',
52: 'yyyy""m""',
53: 'm""d""',
54: 'm""d""',
55: '上午/下午h""mm""',
56: '上午/下午h""mm""ss""',
57: 'yyyy""m""',
58: 'm""d""',
}
# 更新内置格式
BUILTIN_FORMATS.update(extra_formats)
def read_xlsx_file(file_path):
"""
读取Excel文件并输出详细信息
Args:
file_path: Excel文件路径
"""
if not os.path.exists(file_path):
print(f"文件不存在: {file_path}")
return
print(f"正在读取文件: {file_path}")
print("=" * 60)
try:
# 加载工作簿
wb = load_workbook(file_path, data_only=False)
print(f"文件加载成功")
print(f"工作表数量: {len(wb.sheetnames)}")
print(f"工作表名称: {wb.sheetnames}")
print("=" * 60)
# 遍历所有工作表
for sheet_name in wb.sheetnames:
print(f"\n工作表: {sheet_name}")
print("-" * 60)
ws = wb[sheet_name]
# 获取工作表维度
if ws.max_row > 0 and ws.max_column > 0:
print(f"数据范围: {ws.max_row}× {ws.max_column}")
# 读取前10行数据或所有数据如果少于10行
max_display_rows = min(100, ws.max_row)
print(f"\n数据内容(前{max_display_rows}行):")
print("-" * 60)
for row_idx, row in enumerate(ws.iter_rows(min_row=1, max_row=max_display_rows, values_only=False), start=1):
row_data = []
for cell in row:
# 获取单元格值
cell_value = cell.value
# 获取单元格格式信息
cell_info = {
'value': cell_value,
'coordinate': cell.coordinate,
}
# 如果有数字格式,获取格式信息
if cell.number_format:
cell_info['number_format'] = cell.number_format
# 尝试从BUILTIN_FORMATS中查找格式描述
if cell.number_format in BUILTIN_FORMATS.values():
# 查找格式ID
format_id = None
for fmt_id, fmt_str in BUILTIN_FORMATS.items():
if fmt_str == cell.number_format:
format_id = fmt_id
break
if format_id:
cell_info['format_id'] = format_id
# 获取数据类型
if cell_value is not None:
cell_info['data_type'] = type(cell_value).__name__
row_data.append(cell_info)
# 输出行数据
print(f"\n{row_idx}:")
for cell_info in row_data:
value_str = str(cell_info['value']) if cell_info['value'] is not None else '(空)'
coord = cell_info['coordinate']
info_parts = [f" {coord}: {value_str}"]
if 'data_type' in cell_info:
info_parts.append(f"[类型: {cell_info['data_type']}]")
if 'number_format' in cell_info:
fmt = cell_info['number_format']
if 'format_id' in cell_info:
info_parts.append(f"[格式ID: {cell_info['format_id']}, 格式: {fmt}]")
else:
info_parts.append(f"[格式: {fmt}]")
print(" ".join(info_parts))
if ws.max_row > max_display_rows:
print(f"\n... (还有 {ws.max_row - max_display_rows} 行未显示)")
else:
print("工作表为空")
print("\n" + "=" * 60)
print("读取完成")
# 关闭工作簿
wb.close()
except Exception as e:
print(f"读取文件时发生错误: {str(e)}")
import traceback
traceback.print_exc()
def main():
"""主函数"""
# 默认读取example.xlsx如果不存在则尝试其他文件
test_files = [
"test.xlsx"
]
# 查找存在的文件
file_to_read = None
for file in test_files:
if os.path.exists(file):
file_to_read = file
break
if file_to_read:
read_xlsx_file(file_to_read)
else:
print("未找到可用的Excel文件")
print("请将Excel文件放在当前目录或修改main()函数中的文件路径")
print(f"\n当前目录: {os.getcwd()}")
print(f"可用的xlsx文件:")
for root, dirs, files in os.walk('.'):
for file in files:
if file.endswith('.xlsx') and not file.startswith('~$'):
print(f" - {os.path.join(root, file)}")
if __name__ == "__main__":
main()
```