新增blog
This commit is contained in:
270
src/content/posts/note/index.md
Normal file
270
src/content/posts/note/index.md
Normal 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()
|
||||
```
|
||||
Reference in New Issue
Block a user