Add Excel to Markdown converter with support for multiple sheets and customizable output

This commit is contained in:
Misaka_Company
2026-01-20 10:48:52 +08:00
parent 92d4572985
commit 525d2920e3

350
excel_to_markdown.py Normal file
View File

@@ -0,0 +1,350 @@
"""
Excel to Markdown Converter
将Excel文件转换为Markdown格式的表格包含行号和列号英文字母
"""
import pandas as pd
import argparse
import sys
from pathlib import Path
def number_to_excel_col(n):
"""将数字转换为Excel列号A, B, ..., Z, AA, AB, ..."""
result = ""
while n > 0:
n -= 1
result = chr(n % 26 + ord('A')) + result
n //= 26
return result
def excel_to_markdown(input_file, output_file=None, sheet_name=0, include_row_numbers=True, include_col_numbers=True):
"""
将Excel文件转换为Markdown表格
Args:
input_file: 输入的Excel文件路径
output_file: 输出的Markdown文件路径可选默认为同名.md文件
sheet_name: 工作表名称或索引,或列表(默认为第一个工作表)
include_row_numbers: 是否包含行号
include_col_numbers: 是否包含列号
"""
input_path = Path(input_file)
if not input_path.exists():
print(f"错误: 文件 '{input_file}' 不存在")
return False
# 设置默认输出文件名
if output_file is None:
output_file = input_path.with_suffix('.md')
else:
output_file = Path(output_file)
try:
# 读取Excel文件
print(f"正在读取文件: {input_file}")
# 获取所有工作表名称(用于索引转换)
xls = pd.ExcelFile(input_file)
all_sheet_names = xls.sheet_names
# 将索引转换为实际的工作表名称
def resolve_sheet_name(name):
if isinstance(name, int):
if 0 <= name < len(all_sheet_names):
return all_sheet_names[name]
else:
raise ValueError(f"工作表索引 {name} 超出范围")
return name
# 处理多个工作表的情况
if isinstance(sheet_name, (list, tuple)):
# 转换索引为名称
resolved_names = [resolve_sheet_name(s) for s in sheet_name]
dfs = pd.read_excel(input_file, sheet_name=resolved_names, header=None)
# 如果只有一个工作表转换为单个DataFrame
if len(resolved_names) == 1:
dfs = {resolved_names[0]: dfs}
sheet_name = resolved_names
else:
resolved_name = resolve_sheet_name(sheet_name)
df = pd.read_excel(input_file, sheet_name=resolved_name, header=None)
dfs = {resolved_name: df}
sheet_name = resolved_name
# 生成所有工作表的Markdown内容
all_sheets_content = {}
for sheet_key, df in dfs.items():
# 转换数据为字符串处理NaN值
df = df.fillna('')
df = df.astype(str)
# 生成Markdown表格
markdown_lines = []
# 添加工作表标题
sheet_title = f"工作表: {sheet_key}"
markdown_lines.append(f"## {sheet_title}\n")
# 添加列号行
if include_col_numbers:
col_headers = [''] if include_row_numbers else []
col_headers.extend(number_to_excel_col(i + 1) for i in range(len(df.columns)))
markdown_lines.append('| ' + ' | '.join(col_headers) + ' |')
markdown_lines.append('| ' + ' | '.join(['---' for _ in col_headers]) + ' |')
# 添加数据行
for idx, row in df.iterrows():
row_data = []
if include_row_numbers:
row_data.append(str(idx + 1))
row_data.extend(row)
markdown_lines.append('| ' + ' | '.join(row_data) + ' |')
# 添加统计信息
markdown_lines.append(f"\n**统计信息:**")
markdown_lines.append(f"- 总行数: {len(df)}")
markdown_lines.append(f"- 总列数: {len(df.columns)}")
markdown_lines.append(f"- 数据范围: A1:{number_to_excel_col(len(df.columns))}{len(df)}")
all_sheets_content[sheet_key] = '\n'.join(markdown_lines)
# 写入文件
if len(dfs) == 1:
# 单个工作表:直接写入
sheet_key = list(dfs.keys())[0]
output_content = f"# {input_path.stem}\n\n"
output_content += f"从 `{input_file}` (工作表: {sheet_key}) 转换\n\n"
output_content += all_sheets_content[sheet_key]
output_file.write_text(output_content, encoding='utf-8')
print(f"✓ 转换成功!")
print(f" 输入文件: {input_file}")
print(f" 输出文件: {output_file}")
print(f" 工作表: {sheet_key}")
print(f" 行数: {len(dfs[sheet_key])}, 列数: {len(dfs[sheet_key].columns)}")
else:
return all_sheets_content, dfs, input_path, input_file
except Exception as e:
print(f"错误: {str(e)}")
import traceback
traceback.print_exc()
return False
def convert_multiple_sheets(input_file, output_file=None, sheet_names=None, include_row_numbers=True, include_col_numbers=True, merge_to_one_file=True):
"""
转换多个工作表
Args:
input_file: 输入的Excel文件路径
output_file: 输出的Markdown文件路径
sheet_names: 工作表名称或索引列表
include_row_numbers: 是否包含行号
include_col_numbers: 是否包含列号
merge_to_one_file: 是否合并到一个文件True或分别输出False
"""
input_path = Path(input_file)
if not input_path.exists():
print(f"错误: 文件 '{input_file}' 不存在")
return False
# 设置默认输出文件名
if output_file is None:
output_file = input_path.with_suffix('.md')
else:
output_file = Path(output_file)
try:
# 读取Excel文件
print(f"正在读取文件: {input_file}")
# 获取所有工作表名称
xls = pd.ExcelFile(input_file)
all_sheet_names = xls.sheet_names
if sheet_names is None or len(sheet_names) == 0:
# 读取所有工作表
sheet_names = all_sheet_names
print(f"找到 {len(sheet_names)} 个工作表")
else:
# 将索引转换为实际的工作表名称
resolved_names = []
for name in sheet_names:
if isinstance(name, int):
# 索引转换为名称
if 0 <= name < len(all_sheet_names):
resolved_names.append(all_sheet_names[name])
else:
print(f"警告: 工作表索引 {name} 超出范围,已跳过")
else:
# 直接使用名称
resolved_names.append(name)
sheet_names = resolved_names
# 使用实际的工作表名称读取数据
dfs = pd.read_excel(input_file, sheet_name=sheet_names, header=None)
# 确保返回的是字典格式
if not isinstance(dfs, dict):
dfs = {sheet_names[0]: dfs}
# 生成所有工作表的Markdown内容
all_sheets_content = {}
for sheet_key, df in dfs.items():
# 转换数据为字符串处理NaN值
df = df.fillna('')
df = df.astype(str)
# 生成Markdown表格
markdown_lines = []
# 添加工作表标题
sheet_title = f"工作表: {sheet_key}"
markdown_lines.append(f"## {sheet_title}\n")
# 添加列号行
if include_col_numbers:
col_headers = [''] if include_row_numbers else []
col_headers.extend(number_to_excel_col(i + 1) for i in range(len(df.columns)))
markdown_lines.append('| ' + ' | '.join(col_headers) + ' |')
markdown_lines.append('| ' + ' | '.join(['---' for _ in col_headers]) + ' |')
# 添加数据行
for idx, row in df.iterrows():
row_data = []
if include_row_numbers:
row_data.append(str(idx + 1))
row_data.extend(row)
markdown_lines.append('| ' + ' | '.join(row_data) + ' |')
# 添加统计信息
markdown_lines.append(f"\n**统计信息:**")
markdown_lines.append(f"- 总行数: {len(df)}")
markdown_lines.append(f"- 总列数: {len(df.columns)}")
markdown_lines.append(f"- 数据范围: A1:{number_to_excel_col(len(df.columns))}{len(df)}")
all_sheets_content[sheet_key] = '\n'.join(markdown_lines)
# 写入文件
if merge_to_one_file:
# 合并到一个文件
output_content = f"# {input_path.stem}\n\n"
output_content += f"从 `{input_file}` 转换,共 {len(dfs)} 个工作表\n\n"
output_content += "---\n\n"
for sheet_key in sheet_names:
if sheet_key in all_sheets_content:
output_content += all_sheets_content[sheet_key] + "\n\n---\n\n"
output_file.write_text(output_content, encoding='utf-8')
print(f"✓ 转换成功!")
print(f" 输入文件: {input_file}")
print(f" 输出文件: {output_file}")
print(f" 工作表数量: {len(dfs)}")
for sheet_key in sheet_names:
if sheet_key in dfs:
print(f" - {sheet_key}: {len(dfs[sheet_key])}行 x {len(dfs[sheet_key].columns)}")
else:
# 分别输出到多个文件
output_stem = output_file.stem
output_suffix = output_file.suffix
output_dir = output_file.parent
for sheet_key in sheet_names:
if sheet_key not in all_sheets_content:
continue
# 为每个工作表创建单独的文件
sheet_filename = f"{output_stem}_{sheet_key}{output_suffix}"
sheet_output_file = output_dir / sheet_filename
output_content = f"# {input_path.stem} - {sheet_key}\n\n"
output_content += f"从 `{input_file}` (工作表: {sheet_key}) 转换\n\n"
output_content += all_sheets_content[sheet_key]
sheet_output_file.write_text(output_content, encoding='utf-8')
print(f"✓ 转换成功!")
print(f" 输入文件: {input_file}")
print(f" 输出目录: {output_dir}")
print(f" 工作表数量: {len(dfs)}")
for sheet_key in sheet_names:
if sheet_key in dfs:
sheet_filename = f"{output_stem}_{sheet_key}{output_suffix}"
print(f" - {sheet_key} -> {sheet_filename} ({len(dfs[sheet_key])}行 x {len(dfs[sheet_key].columns)}列)")
return True
except Exception as e:
print(f"错误: {str(e)}")
import traceback
traceback.print_exc()
return False
# ============================================================
# 配置区域 - 直接修改下面的参数
# ============================================================
# 输入文件路径(必填)
INPUT_FILE = r"D:\python\playwrite\data\YTHN-100.A0.532-BOM-1.2版.xlsx"
# 输出文件路径(可选,默认为输入文件同名.md文件
OUTPUT_FILE = None # 或指定 r"D:\path\to\output.md"
# 工作表名称或索引可选默认为0即第一个工作表
# 可以是单个值: 0 或 "Sheet1"
# 可以是列表: [0, 1, 2] 或 ["Sheet1", "Sheet2", "Sheet3"]
# 可以是 None 表示读取所有工作表
SHEET_NAMES = [0, 1,2,3] # 指定多个工作表索引
# 是否包含行号可选默认为True
INCLUDE_ROW_NUMBERS = True
# 是否包含列号可选默认为True
INCLUDE_COL_NUMBERS = True
# 如果指定了多个工作表是否合并到一个文件可选默认为True
# True: 所有工作表合并到一个文件
# False: 每个工作表生成单独的文件(文件名格式: 原文件名_工作表名.md
MULTI_SHEETS_TO_ONE_FILE = True
# ============================================================
def main():
"""主函数 - 使用上方配置区域定义的参数"""
# 判断是否为多个工作表
if isinstance(SHEET_NAMES, list) and len(SHEET_NAMES) > 1:
# 多个工作表
convert_multiple_sheets(
input_file=INPUT_FILE,
output_file=OUTPUT_FILE,
sheet_names=SHEET_NAMES,
include_row_numbers=INCLUDE_ROW_NUMBERS,
include_col_numbers=INCLUDE_COL_NUMBERS,
merge_to_one_file=MULTI_SHEETS_TO_ONE_FILE
)
else:
# 单个工作表
sheet_name = SHEET_NAMES if isinstance(SHEET_NAMES, list) and len(SHEET_NAMES) == 1 else SHEET_NAMES
excel_to_markdown(
input_file=INPUT_FILE,
output_file=OUTPUT_FILE,
sheet_name=sheet_name,
include_row_numbers=INCLUDE_ROW_NUMBERS,
include_col_numbers=INCLUDE_COL_NUMBERS
)
if __name__ == '__main__':
main()