Add excel-to-markdown skill and converter script

- Add excel_to_markdown.py script for converting Excel files to Markdown tables
- Create excel-to-markdown skill with SKILL.md documentation
- Support automatic data range detection and flexible output options
- Include features for row/column numbering and partial conversions
- Add skill-creator reference documentation

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Misaka Company
2026-01-27 12:54:34 +08:00
commit b017e36753
4 changed files with 604 additions and 0 deletions

43
.gitignore vendored Normal file
View File

@@ -0,0 +1,43 @@
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
# UV
.venv/
uv.lock
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# Project specific
*.xlsx
*.xls
# .claude
.claude/

View File

@@ -0,0 +1,220 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Excel to Markdown Converter
将Excel文档转换为Markdown表格格式
"""
import openpyxl
from openpyxl.utils import get_column_letter
from typing import Optional, Tuple
import argparse
class ExcelToMarkdown:
"""Excel转Markdown转换器"""
def __init__(self, excel_file: str):
"""
初始化转换器
Args:
excel_file: Excel文件路径
"""
self.workbook = openpyxl.load_workbook(excel_file, data_only=True)
self.sheet = self.workbook.active
def detect_data_range(self, max_scan_rows: int = 100, max_scan_cols: int = 100) -> Tuple[int, int]:
"""
自动检测数据范围
Args:
max_scan_rows: 最大扫描行数
max_scan_cols: 最大扫描列数
Returns:
(最大行号, 最大列号)
"""
max_row = 0
max_col = 0
# 扫描前100行和前100列
scan_rows = min(max_scan_rows, self.sheet.max_row)
scan_cols = min(max_scan_cols, self.sheet.max_column)
for row in range(1, scan_rows + 1):
for col in range(1, scan_cols + 1):
cell_value = self.sheet.cell(row=row, column=col).value
if cell_value is not None and str(cell_value).strip() != "":
max_row = max(max_row, row)
max_col = max(max_col, col)
return max_row, max_col
def convert(self,
max_rows: Optional[int] = None,
max_cols: Optional[int] = None,
show_row_numbers: bool = False,
show_col_numbers: bool = False,
start_row: int = 1,
start_col: int = 1) -> str:
"""
转换Excel为Markdown格式
Args:
max_rows: 最大行数None表示自动检测
max_cols: 最大列数None表示自动检测
show_row_numbers: 是否显示行号
show_col_numbers: 是否显示列号(字母形式)
start_row: 起始行号默认1
start_col: 起始列号默认1
Returns:
Markdown格式的表格字符串
"""
# 自动检测数据范围
if max_rows is None or max_cols is None:
detected_rows, detected_cols = self.detect_data_range()
if max_rows is None:
max_rows = detected_rows
if max_cols is None:
max_cols = detected_cols
# 确保至少有1行1列
if max_rows < 1 or max_cols < 1:
return "| 无数据 |\n|--------|\n"
# 计算实际的结束位置
end_row = min(start_row + max_rows - 1, self.sheet.max_row)
end_col = min(start_col + max_cols - 1, self.sheet.max_column)
markdown_lines = []
# 构建列号行(如果需要)
if show_col_numbers:
header_parts = []
if show_row_numbers:
header_parts.append("") # 行号列的占位
for col in range(start_col, end_col + 1):
col_letter = get_column_letter(col)
header_parts.append(col_letter)
markdown_lines.append("| " + " | ".join(header_parts) + " |")
# 分隔线
separator_parts = ["---"] * len(header_parts)
markdown_lines.append("| " + " | ".join(separator_parts) + " |")
# 构建数据行
for row in range(start_row, end_row + 1):
row_parts = []
# 添加行号(如果需要)
if show_row_numbers:
row_parts.append(str(row))
# 添加单元格数据
for col in range(start_col, end_col + 1):
cell_value = self.sheet.cell(row=row, column=col).value
# 处理空值
if cell_value is None:
cell_str = ""
else:
cell_str = str(cell_value).strip()
# 转义Markdown特殊字符
cell_str = cell_str.replace("|", "\\|")
cell_str = cell_str.replace("\n", "<br>")
row_parts.append(cell_str)
markdown_lines.append("| " + " | ".join(row_parts) + " |")
# 如果是第一行且没有显示列号,添加分隔线
if row == start_row and not show_col_numbers:
separator_parts = ["---"] * len(row_parts)
markdown_lines.append("| " + " | ".join(separator_parts) + " |")
return "\n".join(markdown_lines)
def save_to_file(self, markdown_text: str, output_file: str):
"""
保存Markdown到文件
Args:
markdown_text: Markdown文本
output_file: 输出文件路径
"""
with open(output_file, 'w', encoding='utf-8') as f:
f.write(markdown_text)
def close(self):
"""关闭工作簿"""
self.workbook.close()
def main():
"""命令行入口"""
parser = argparse.ArgumentParser(
description='将Excel文档转换为Markdown表格格式',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
示例:
# 自动检测范围并转换
python excel_to_markdown.py input.xlsx -o output.md
# 指定转换前10行、前5列
python excel_to_markdown.py input.xlsx -o output.md -r 10 -c 5
# 显示行号和列号
python excel_to_markdown.py input.xlsx -o output.md --show-rows --show-cols
# 从第2行第2列开始转换5行3列
python excel_to_markdown.py input.xlsx -o output.md -r 5 -c 3 --start-row 2 --start-col 2
"""
)
parser.add_argument('input_file', help='输入的Excel文件路径')
parser.add_argument('-o', '--output', help='输出的Markdown文件路径不指定则输出到控制台')
parser.add_argument('-r', '--max-rows', type=int, help='最大转换行数(不指定则自动检测)')
parser.add_argument('-c', '--max-cols', type=int, help='最大转换列数(不指定则自动检测)')
parser.add_argument('--show-rows', action='store_true', help='显示行号')
parser.add_argument('--show-cols', action='store_true', help='显示列号(字母形式)')
parser.add_argument('--start-row', type=int, default=1, help='起始行号默认1')
parser.add_argument('--start-col', type=int, default=1, help='起始列号默认1')
args = parser.parse_args()
try:
# 创建转换器
converter = ExcelToMarkdown(args.input_file)
# 执行转换
markdown_text = converter.convert(
max_rows=args.max_rows,
max_cols=args.max_cols,
show_row_numbers=args.show_rows,
show_col_numbers=args.show_cols,
start_row=args.start_row,
start_col=args.start_col
)
# 输出结果
if args.output:
converter.save_to_file(markdown_text, args.output)
print(f"✓ 转换完成!已保存到: {args.output}")
else:
print(markdown_text)
# 关闭工作簿
converter.close()
except FileNotFoundError:
print(f"✗ 错误: 找不到文件 '{args.input_file}'")
except Exception as e:
print(f"✗ 错误: {str(e)}")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,121 @@
---
name: excel-to-markdown
description: Convert Excel (.xlsx, .xls) files to Markdown table format. Use for converting Excel documents to Markdown for display or documentation, extracting and analyzing Excel data in a structured format, processing Excel files with automatic data range detection, generating Markdown tables with optional row/column numbering, or handling partial conversions with specific row/column ranges. Triggered by requests like "convert this Excel to Markdown", "export Excel as MD", "analyze this spreadsheet", or when working with .xlsx/.xls files that need to be viewed or processed as text.
---
# Excel to Markdown Converter
## Overview
Convert Excel spreadsheets to Markdown table format with automatic data range detection and flexible output options. The converter handles complex multi-sheet workbooks, preserves cell formatting, and can display row/column numbers for easy reference.
## Quick Start
### Basic Conversion
Convert an entire Excel file to Markdown:
```bash
python3 scripts/excel_to_markdown.py input.xlsx -o output.md
```
### Convert with Row/Column Numbers
Display Excel row and column identifiers for reference:
```bash
python3 scripts/excel_to_markdown.py input.xlsx -o output.md --show-rows --show-cols
```
### Specify Data Range
Convert only a specific portion of the spreadsheet:
```bash
# Convert first 10 rows and 5 columns
python3 scripts/excel_to_markdown.py input.xlsx -o output.md -r 10 -c 5
# Start from row 2, column 3, convert 20 rows
python3 scripts/excel_to_markdown.py input.xlsx -o output.md --start-row 2 --start-col 3 -r 20
```
## Command Line Options
| Option | Description |
|--------|-------------|
| `input_file` | Path to the Excel file (required) |
| `-o, --output` | Output Markdown file path (optional, prints to console if not specified) |
| `-r, --max-rows` | Maximum number of rows to convert (auto-detect if not specified) |
| `-c, --max-cols` | Maximum number of columns to convert (auto-detect if not specified) |
| `--show-rows` | Display row numbers in the first column |
| `--show-cols` | Display column letters (A, B, C...) in the first row |
| `--start-row` | Starting row number (default: 1) |
| `--start-col` | Starting column number (default: 1) |
## Features
### Automatic Data Range Detection
The converter automatically scans the spreadsheet to identify the actual data range (up to 100 rows and 100 columns by default), ignoring empty trailing rows and columns.
### Cell Content Handling
- Empty cells are rendered as blank
- Pipe characters (`|`) in cell content are escaped as `\|`
- Newlines within cells are converted to `<br>` tags
- All cell values are trimmed of leading/trailing whitespace
### Multi-Sheet Support
By default, the converter processes the active (last selected) sheet in the workbook.
## Common Use Cases
### 1. Data Analysis
Extract Excel data for analysis or processing:
```bash
python3 scripts/excel_to_markdown.py sales_data.xlsx -o sales_analysis.md
```
Then analyze the Markdown output or provide insights based on the structured data.
### 2. Documentation
Convert spreadsheets to Markdown for inclusion in documentation:
```bash
python3 scripts/excel_to_markdown.py specifications.xlsx -o specs.md --show-rows --show-cols
```
The row/column numbers make it easy to reference specific cells in documentation.
### 3. Quick Preview
Quickly view Excel contents without opening a spreadsheet application:
```bash
python3 scripts/excel_to_markdown.py report.xlsx
```
### 4. Partial Data Extraction
Extract specific sections from large spreadsheets:
```bash
# Get header row and first 10 data rows
python3 scripts/excel_to_markdown.py large_file.xlsx -o sample.md -r 11
```
## Script Location
The converter script is located at: `scripts/excel_to_markdown.py`
## Dependencies
The script requires `openpyxl` for Excel file processing:
```bash
pip install openpyxl
```

View File

@@ -0,0 +1,220 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Excel to Markdown Converter
将Excel文档转换为Markdown表格格式
"""
import openpyxl
from openpyxl.utils import get_column_letter
from typing import Optional, Tuple
import argparse
class ExcelToMarkdown:
"""Excel转Markdown转换器"""
def __init__(self, excel_file: str):
"""
初始化转换器
Args:
excel_file: Excel文件路径
"""
self.workbook = openpyxl.load_workbook(excel_file, data_only=True)
self.sheet = self.workbook.active
def detect_data_range(self, max_scan_rows: int = 100, max_scan_cols: int = 100) -> Tuple[int, int]:
"""
自动检测数据范围
Args:
max_scan_rows: 最大扫描行数
max_scan_cols: 最大扫描列数
Returns:
(最大行号, 最大列号)
"""
max_row = 0
max_col = 0
# 扫描前100行和前100列
scan_rows = min(max_scan_rows, self.sheet.max_row)
scan_cols = min(max_scan_cols, self.sheet.max_column)
for row in range(1, scan_rows + 1):
for col in range(1, scan_cols + 1):
cell_value = self.sheet.cell(row=row, column=col).value
if cell_value is not None and str(cell_value).strip() != "":
max_row = max(max_row, row)
max_col = max(max_col, col)
return max_row, max_col
def convert(self,
max_rows: Optional[int] = None,
max_cols: Optional[int] = None,
show_row_numbers: bool = False,
show_col_numbers: bool = False,
start_row: int = 1,
start_col: int = 1) -> str:
"""
转换Excel为Markdown格式
Args:
max_rows: 最大行数None表示自动检测
max_cols: 最大列数None表示自动检测
show_row_numbers: 是否显示行号
show_col_numbers: 是否显示列号(字母形式)
start_row: 起始行号默认1
start_col: 起始列号默认1
Returns:
Markdown格式的表格字符串
"""
# 自动检测数据范围
if max_rows is None or max_cols is None:
detected_rows, detected_cols = self.detect_data_range()
if max_rows is None:
max_rows = detected_rows
if max_cols is None:
max_cols = detected_cols
# 确保至少有1行1列
if max_rows < 1 or max_cols < 1:
return "| 无数据 |\n|--------|\n"
# 计算实际的结束位置
end_row = min(start_row + max_rows - 1, self.sheet.max_row)
end_col = min(start_col + max_cols - 1, self.sheet.max_column)
markdown_lines = []
# 构建列号行(如果需要)
if show_col_numbers:
header_parts = []
if show_row_numbers:
header_parts.append("") # 行号列的占位
for col in range(start_col, end_col + 1):
col_letter = get_column_letter(col)
header_parts.append(col_letter)
markdown_lines.append("| " + " | ".join(header_parts) + " |")
# 分隔线
separator_parts = ["---"] * len(header_parts)
markdown_lines.append("| " + " | ".join(separator_parts) + " |")
# 构建数据行
for row in range(start_row, end_row + 1):
row_parts = []
# 添加行号(如果需要)
if show_row_numbers:
row_parts.append(str(row))
# 添加单元格数据
for col in range(start_col, end_col + 1):
cell_value = self.sheet.cell(row=row, column=col).value
# 处理空值
if cell_value is None:
cell_str = ""
else:
cell_str = str(cell_value).strip()
# 转义Markdown特殊字符
cell_str = cell_str.replace("|", "\\|")
cell_str = cell_str.replace("\n", "<br>")
row_parts.append(cell_str)
markdown_lines.append("| " + " | ".join(row_parts) + " |")
# 如果是第一行且没有显示列号,添加分隔线
if row == start_row and not show_col_numbers:
separator_parts = ["---"] * len(row_parts)
markdown_lines.append("| " + " | ".join(separator_parts) + " |")
return "\n".join(markdown_lines)
def save_to_file(self, markdown_text: str, output_file: str):
"""
保存Markdown到文件
Args:
markdown_text: Markdown文本
output_file: 输出文件路径
"""
with open(output_file, 'w', encoding='utf-8') as f:
f.write(markdown_text)
def close(self):
"""关闭工作簿"""
self.workbook.close()
def main():
"""命令行入口"""
parser = argparse.ArgumentParser(
description='将Excel文档转换为Markdown表格格式',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
示例:
# 自动检测范围并转换
python excel_to_markdown.py input.xlsx -o output.md
# 指定转换前10行、前5列
python excel_to_markdown.py input.xlsx -o output.md -r 10 -c 5
# 显示行号和列号
python excel_to_markdown.py input.xlsx -o output.md --show-rows --show-cols
# 从第2行第2列开始转换5行3列
python excel_to_markdown.py input.xlsx -o output.md -r 5 -c 3 --start-row 2 --start-col 2
"""
)
parser.add_argument('input_file', help='输入的Excel文件路径')
parser.add_argument('-o', '--output', help='输出的Markdown文件路径不指定则输出到控制台')
parser.add_argument('-r', '--max-rows', type=int, help='最大转换行数(不指定则自动检测)')
parser.add_argument('-c', '--max-cols', type=int, help='最大转换列数(不指定则自动检测)')
parser.add_argument('--show-rows', action='store_true', help='显示行号')
parser.add_argument('--show-cols', action='store_true', help='显示列号(字母形式)')
parser.add_argument('--start-row', type=int, default=1, help='起始行号默认1')
parser.add_argument('--start-col', type=int, default=1, help='起始列号默认1')
args = parser.parse_args()
try:
# 创建转换器
converter = ExcelToMarkdown(args.input_file)
# 执行转换
markdown_text = converter.convert(
max_rows=args.max_rows,
max_cols=args.max_cols,
show_row_numbers=args.show_rows,
show_col_numbers=args.show_cols,
start_row=args.start_row,
start_col=args.start_col
)
# 输出结果
if args.output:
converter.save_to_file(markdown_text, args.output)
print(f"✓ 转换完成!已保存到: {args.output}")
else:
print(markdown_text)
# 关闭工作簿
converter.close()
except FileNotFoundError:
print(f"✗ 错误: 找不到文件 '{args.input_file}'")
except Exception as e:
print(f"✗ 错误: {str(e)}")
if __name__ == "__main__":
main()