- 支持 .xls (BIFF8) 和 .xlsx 格式 - GUI 文件选择 + 命令行双模式 - 智能结构验证(重复/间隙/空单元格检测) - 逆时针 PinMAP → 顺时针 PinList 自动转换 - Python 标准库,零第三方依赖
28 KiB
PinMAP → PinList 转换器 — 全局架构设计
版本: v1.0
日期: 2026-05-25
架构师: 脚本架构师 (Script Architect)
状态: 待审批
1. 项目概述
1.1 背景
将 Excel 格式的 PinMAP 文件(方形封装引脚布局图)自动转换为 PinList 格式(引脚序号列表),消除手动抄录的低效与错误风险。
1.2 核心规则
- PinMAP 为方形/长方形结构,引脚沿四条边分布,左上角为 1 脚,逆时针排序
- 左上角 = 1 脚,右上角 = 上边最后一个脚,右下角 = 下边最后一个脚,左下角 = 左边最后一个脚
- 四个角点被相邻两边共享(不重复计数)
1.3 约束
| 约束项 | 说明 |
|---|---|
| 运行平台 | Windows |
| 技术栈 | Python 标准库,零第三方依赖 |
| 输入格式 | .xls(必须支持)、.xlsx(优先支持) |
| 输出格式 | .xlsx 仅 |
| 交互方式 | 命令行 + 文件选择对话框 |
2. 技术选型
2.1 为什么不用 openpyxl / xlrd?
项目明确要求 无第三方依赖,因此必须使用 Python 标准库自行实现 Excel 读写。
2.2 XLS 读取 — BIFF8 二进制解析
.xls 是 Microsoft BIFF8 二进制格式(复合文档 OLE2 容器)。
实现策略:
1. 使用 struct 模块解析 OLE2 复合文档头
2. 解析 FAT(文件分配表)定位 MiniFAT 和目录流
3. 定位 Workbook 流,读取 BIFF8 记录序列
4. 关键记录类型:
- 0x0009 (BOF) → 块起始标记
- 0x00FD (LABELSST) → 共享字符串表中的文本单元格
- 0x0006 (FORMULA) → 公式/数值单元格
- 0x0203 (NUMBER) → 数值单元格
- 0x000C (RK) → RK 数值(压缩整数/浮点)
- 0x000D (RString) → 内联字符串
- 0x00FC (STRING) → 字符串结果
- 0x0034 (SST) → 全局共享字符串表
- 0x0042 (BOUNDSHEET) → 工作表信息
5. 提取每个单元格的 (行, 列, 值) 三元组
复杂度评估:中等。BIFF8 是固定长度记录流,struct 解析直接。需处理 Unicode 编码(BIFF8 默认 UTF-16LE,部分兼容 ASCII)。
2.3 XLSX 读取 — ZIP + XML
.xlsx 本质是 ZIP 压缩包,内部为 Office Open XML (OOXML)。
实现策略:
import zipfile
import xml.etree.ElementTree as ET
1. zipfile.ZipFile 打开 .xlsx
2. 读取 [Content_Types].xml 确认结构
3. 读取 xl/workbook.xml 获取工作表关系
4. 读取 xl/worksheets/sheet1.xml 获取单元格数据
5. 读取 xl/sharedStrings.xml 获取共享字符串表
6. 解析单元格坐标(如 "A2" → 列A行2)和值类型
复杂度评估:低。zipfile 和 xml.etree 均为标准库,XML 结构规范清晰。
2.4 XLSX 写入 — ZIP + XML 生成
实现策略:
import zipfile
import xml.etree.ElementTree as ET
from io import BytesIO
1. 构建 OOXML 目录结构:
[Content_Types].xml
_rels/.rels
xl/workbook.xml
xl/worksheets/sheet1.xml
xl/sharedStrings.xml
xl/_rels/workbook.xml.rels
2. 使用 zipfile.ZipFile 写入(ZIP_DEFLATED)
3. 关键 XML 构建:
- sharedStrings.xml: 所有唯一字符串的 SST
- sheet1.xml: 单元格坐标 + si (SST index) 引用
- workbook.xml: 工作表引用
- [Content_Types].xml: MIME 类型声明
复杂度评估:低。XML 结构固定,模板化生成即可。
2.5 技术选型总结
| 操作 | 格式 | 标准库模块 | 难度 |
|---|---|---|---|
| 读取 | xls | struct + 手动 OLE2/BIFF8 解析 |
中 |
| 读取 | xlsx | zipfile + xml.etree.ElementTree |
低 |
| 写入 | xlsx | zipfile + xml.etree.ElementTree |
低 |
| 文件选择 | — | tkinter.filedialog |
低 |
3. 模块划分
pinmap-to-pinlist/
├── Code/
│ ├── src/
│ │ ├── main.py # 入口:流程编排
│ │ ├── file_selector.py # 模块1:文件选择
│ │ ├── xls_reader.py # 模块2a:XLS 解析引擎
│ │ ├── xlsx_reader.py # 模块2b:XLSX 解析引擎
│ │ ├── pinmap_parser.py # 模块3:PinMAP 结构解析
│ │ ├── validator.py # 模块4:数据验证
│ │ ├── pinlist_generator.py # 模块5:PinList 生成
│ │ └── xlsx_writer.py # 模块6:XLSX 输出引擎
│ └── docs/
│ └── architecture-design.md
├── Test/
└── Releases/
3.1 模块职责
模块1:file_selector — 文件选择
def select_file() -> str | None:
"""弹出文件选择对话框,返回选中文件路径或 None(取消)"""
- 使用
tkinter.filedialog.askopenfilename - 文件类型过滤:
*.xls;*.xlsx - 无 GUI 环境时回退到命令行参数
模块2a:xls_reader — XLS 解析引擎
class XLSReader:
def __init__(self, filepath: str)
def read_all_cells(self) -> dict[tuple[int, int], str]:
"""返回 {(row, col): value} 字典,行列从 0 开始"""
def close(self)
内部结构:
XLSReader
├── OLE2Parser → 解析复合文档,定位 Workbook 流
├── BIFF8Parser → 解析 BIFF8 记录流
│ ├── SSTParser → 共享字符串表
│ └── CellParser → 单元格记录
└── CellMap → 组装为 (row, col) → value 映射
模块2b:xlsx_reader — XLSX 解析引擎
class XLSXReader:
def __init__(self, filepath: str)
def read_all_cells(self) -> dict[tuple[int, int], str]:
"""返回 {(row, col): value} 字典,行列从 0 开始"""
def close(self)
内部结构:
XLSXReader
├── ZipExtractor → 解压 .xlsx 到内存
├── SharedStrings → 解析 sharedStrings.xml
├── SheetParser → 解析 sheet1.xml
│ ├── CoordParser → 列字母转索引 (A→0, B→1, ...)
│ └── CellParser → 提取单元格值
└── CellMap → 组装为 (row, col) → value 映射
模块3:pinmap_parser — PinMAP 结构解析
def parse_pinmap(cells: dict[tuple[int, int], str]) -> PinMAP:
"""
解析步骤:
1. 排除 (0,0) 后扫描非空单元格,确定方形边界
2. 提取 A1 封装信息
3. 沿四条边提取引脚序号(边界单元格)和 PinName(相邻内侧单元格)
4. 逆时针遍历(左→下→右→上),按单元格位置去重(角点共享)
5. 返回 PinMAP 对象
"""
解析算法:
Step 1: 确定方形边界
- 排除 (0,0)(封装信息单元格)
- 扫描所有非空单元格,找到最小/最大行号和列号
- width = max_col - min_col + 1
- height = max_row - min_row + 1
- 验证:width >= 2 且 height >= 2
Step 2: 提取 A1 封装信息
- cells[(0, 0)] → package_info
Step 3: 构建 PinName 查找表
每条边的 PinName 位于序号单元格的"内侧相邻"位置:
左边:序号在 (r, min_col), Name 在 (r, min_col+1)
下边:序号在 (max_row, c), Name 在 (max_row-1, c)
右边:序号在 (r, max_col), Name 在 (r, max_col-1)
上边:序号在 (min_row, c), Name 在 (min_row+1, c)
Step 4: 逆时针遍历四条边(按单元格位置去重)
4a. 左边:从上到下 (row: min_row → max_row, col: min_col)
4b. 下边:从左到右 (row: max_row, col: min_col+1 → max_col)
4c. 右边:从下到上 (row: max_row-1 → min_row, col: max_col)
4d. 上边:从右到左 (row: min_row, col: max_col-1 → min_col)
角点去重:按 (row, col) 单元格位置去重,而非按 Pin 序号。
这样如果两个不同单元格恰好有相同序号,validator 能检测到。
Step 5: 组装 Pin 列表
按逆时针顺序:Pin1(左上角) → Pin2 → ... → PinN
模块4:validator — 数据验证
def validate_pinmap(pinmap: PinMAP) -> ValidationResult:
"""
验证项:
1. Pin序号唯一性(无重复)
2. Pin序号连续性(1..N 无间隔)
3. PinName 缺失检测(warning,默认 NC)
4. 方形结构完整性(width/height >= 2)
"""
模块5:pinlist_generator — PinList 生成
class PinListGenerator:
def __init__(self, pinmap: PinMAP, validation: ValidationResult)
def generate(self) -> PinList:
"""
生成规则:
- A1 = 封装信息
- A列 = PinName
- B列 = Pin序号
- 按 Pin序号 递增排序
"""
模块6:xlsx_writer — XLSX 输出引擎
class XLSXWriter:
def __init__(self)
def write_pinlist(self, pinlist: PinList, output_path: str)
3.2 模块依赖关系
main.py
├── file_selector.py
├── xls_reader.py ──┐
├── xlsx_reader.py ─┤
│ ▼
│ pinmap_parser.py
│ ▼
│ validator.py
│ ▼
│ pinlist_generator.py
│ ▼
└─────────── xlsx_writer.py
4. 数据结构设计
4.1 Pin(引脚)
@dataclass
class Pin:
number: int # 引脚序号(1-based)
name: str # 引脚名称(缺失时默认为 "NC")
edge: str # 所在边: "top" | "right" | "bottom" | "left"
position_on_edge: int # 在该边上的位置(0-based)
4.2 PinMAP(引脚映射图)
@dataclass
class PinMAP:
package_info: str # A1 单元格封装信息
pins: list[Pin] # 所有引脚(按序号排序)
width: int # 方形宽度(列数)
height: int # 方形高度(行数)
grid_origin: tuple[int, int] # (row, col) 方形左上角
raw_cells: dict[tuple[int, int], str] # 原始单元格数据(调试用)
4.3 PinList(引脚列表)
@dataclass
class PinList:
package_info: str # 输出 A1 单元格
rows: list[tuple[str, int]] # [(PinName, Pin序号), ...] 按序号排序
4.4 ValidationResult(验证结果)
@dataclass
class ValidationError:
level: str # "error" | "warning"
message: str # 错误描述
details: str # 详细信息(如重复的序号、缺失的Pin等)
@dataclass
class ValidationResult:
is_valid: bool
errors: list[ValidationError]
warnings: list[ValidationError]
4.5 内部:单元格坐标体系
统一使用 (row, col) 元组,0-based:
- row 0 = Excel 第1行
- col 0 = Excel A列
- A1 = (0, 0)
- A2 = (1, 0)
- C2 = (1, 2)
- B4 = (3, 1)
5. 异常处理策略
5.1 异常分类
| 级别 | 类型 | 处理方式 | 示例 |
|---|---|---|---|
| FATAL | 文件格式错误 | 终止 + 错误信息 | 非Excel文件、BIFF损坏 |
| FATAL | 结构错误 | 终止 + 错误信息 | 非方形、缺少A1、无边数据 |
| ERROR | 数据错误 | 终止 + 详细错误 | 序号不连续、序号重复 |
| WARN | 数据警告 | 提示 + 继续 | PinName缺失(默认NC) |
| INFO | 信息提示 | 仅显示 | 转换完成、统计信息 |
5.2 自定义异常层次
class PinMapError(Exception):
"""基类异常"""
class FileFormatError(PinMapError):
"""文件格式错误(非xls/xlsx、文件损坏)"""
class StructureError(PinMapError):
"""PinMAP结构错误(非方形、缺少必要数据)"""
class ValidationError(PinMapError):
"""数据验证错误(序号不连续、重复)"""
class WarningLevel(PinMapError):
"""警告级别(PinName缺失等,可继续处理)"""
5.3 错误信息规范
[级别] 错误类别: 具体描述
详细信息: ...
建议操作: ...
示例:
[ERROR] 序号不连续: 检测到序号间断
预期: 1,2,3,4,5,6 实际: 1,2,3,5,6
缺失序号: 4
建议: 检查PinMAP文件中是否有遗漏的引脚
[WARN] PinName缺失: 检测到 3 个引脚缺少PinName
缺失引脚: Pin 7, Pin 12, Pin 18
处理: 已自动设为 "NC"
5.4 主流程异常处理
def main():
try:
filepath = select_file()
if not filepath:
return # 用户取消
cells = read_excel(filepath)
pinmap = parse_pinmap(cells)
result = validate(pinmap)
if result.has_errors():
print_errors(result.errors)
return
if result.has_warnings():
print_warnings(result.warnings)
if not confirm_continue():
return
pinlist = generate(pinmap, result)
output_path = build_output_path(filepath)
write_xlsx(pinlist, output_path)
print_success(output_path)
except FileFormatError as e:
print_fatal(f"文件格式错误: {e}")
except StructureError as e:
print_fatal(f"结构错误: {e}")
except ValidationError as e:
print_fatal(f"数据验证失败: {e}")
except Exception as e:
print_fatal(f"未知错误: {e}")
6. 文件处理流程图
┌─────────────────────────────────────────────────────────────────┐
│ 主流程 (main.py) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌───────────────────────────┐
│ 1. 文件选择 (file_selector) │
│ - tkinter 文件对话框 │
│ - 过滤 *.xls, *.xlsx │
└───────────┬───────────────┘
│
┌───────────▼───────────────┐
│ 2. 读取 Excel 文件 │
│ ┌─────────────────────┐ │
│ │ 判断文件格式 │ │
│ │ .xls → xls_reader │ │
│ │ .xlsx → xlsx_reader│ │
│ └─────────┬───────────┘ │
│ ┌─────────▼───────────┐ │
│ │ 解析为单元格字典 │ │
│ │ {(row,col): value} │ │
│ └─────────┬───────────┘ │
└────────────┬──────────────┘
│
┌────────────▼──────────────┐
│ 3. PinMAP 解析 (pinmap_parser) │
│ ┌─────────────────────┐ │
│ │ ① 定位方形边界 │ │
│ │ 扫描非空单元格 │ │
│ │ 确定 width/height│ │
│ └─────────┬───────────┘ │
│ ┌─────────▼───────────┐ │
│ │ ② 提取 A1 封装信息 │ │
│ └─────────┬───────────┘ │
│ ┌─────────▼───────────┐ │
│ │ ③ 沿四边提取引脚 │ │
│ │ 上边 → 右边 │ │
│ │ 下边 → 左边 │ │
│ │ 逆时针排序 │ │
│ └─────────┬───────────┘ │
│ ┌─────────▼───────────┐ │
│ │ ④ 组装 PinMAP 对象 │ │
│ └─────────┬───────────┘ │
└────────────┬──────────────┘
│
┌────────────▼──────────────┐
│ 4. 数据验证 (validator) │
│ ┌─────────────────────┐ │
│ │ ✓ 序号连续性检查 │ │
│ │ ✓ 序号唯一性检查 │ │
│ │ ✓ PinName 缺失检查 │ │
│ │ ✓ 方形结构完整性 │ │
│ └─────────┬───────────┘ │
│ ┌─────────▼───────────┐ │
│ │ ERROR → 终止流程 │ │
│ │ WARN → 提示确认 │ │
│ └─────────┬───────────┘ │
└────────────┬──────────────┘
│
┌────────────▼──────────────┐
│ 5. PinList 生成 (generator) │
│ ┌─────────────────────┐ │
│ │ A1 = 封装信息 │ │
│ │ A列 = PinName │ │
│ │ B列 = Pin序号 │ │
│ │ 按序号递增排序 │ │
│ └─────────┬───────────┘ │
└────────────┬──────────────┘
│
┌────────────▼──────────────┐
│ 6. XLSX 输出 (xlsx_writer) │
│ ┌─────────────────────┐ │
│ │ 构建 OOXML 结构 │ │
│ │ [Content_Types].xml │ │
│ │ xl/workbook.xml │ │
│ │ xl/sharedStrings.xml│ │
│ │ xl/worksheets/ │ │
│ │ sheet1.xml │ │
│ └─────────┬───────────┘ │
│ ┌─────────▼───────────┐ │
│ │ ZIP 打包输出 │ │
│ └─────────┬───────────┘ │
└────────────┬──────────────┘
│
▼
┌───────────────────────────┐
│ 完成!输出 .xlsx 文件 │
│ 默认命名: {原文件名}_PinList.xlsx │
└───────────────────────────┘
7. PinMAP 结构详解
7.1 坐标映射
以 4×4 方形为例(width=4, height=4):
col A(0) col B(1) col C(2) col D(3)
row 0 [A1=封装] [PinName] [PinName] [PinName] ← 上边PinName行
row 1 [1] [2] [3] [4] ← 上边Pin序号行
row 2 [PinName] [ ] [PinName] ← 中间区域(留空)
row 3 [PinName] [ ] [PinName] ← 中间区域(留空)
row 4 [13] [12] [11] [10] ← 下边Pin序号行
[PinName] [PinName] [PinName] [PinName] ← 下边PinName行(行5)
↑ ↑ ↑ ↑
左边 左边 右边 右边
PinName PinName PinName PinName
(列前) (列前) (列后) (列后)
实际引脚分布:
- 上边:Pin 1(A,row1) → Pin 2(B,row1) → Pin 3(C,row1) → Pin 4(D,row1)
- 右边:Pin 5(D,row2) → Pin 6(D,row3) → Pin 7(D,row4)
- 下边:Pin 8(D,row4) ... 等等
等等,让我重新理清。根据需求描述:
C2 是上边最后一个Pin序号,C3是对应PinName
A4 是左边第一个Pin序号,B4是对应PinName
这说明:
- 行1(Excel第2行)= 上边Pin序号行
- 行2(Excel第3行)= 上边PinName行
- 行3(Excel第4行)= 左边第一个Pin序号行
所以方形区域从 row=1 开始(Excel第2行),row=0 是PinName行。
7.2 四边提取规则(修正版)
设方形区域:行范围 [r_top, r_bottom],列范围 [c_left, c_right]
上边 (Top Edge):
Pin序号位置:row=r_top, col=c_left → c_right(从左到右)
PinName位置:row=r_top-1, col=c_left → c_right
右边 (Right Edge):
Pin序号位置:col=c_right, row=r_top → r_bottom(从上到下)
PinName位置:col=c_right+1, row=r_top → r_bottom
下边 (Bottom Edge):
Pin序号位置:row=r_bottom, col=c_right → c_left(从右到左)
PinName位置:row=r_bottom+1, col=c_right → c_left
左边 (Left Edge):
Pin序号位置:col=c_left, row=r_bottom → r_top(从下到上)
PinName位置:col=c_left-1, row=r_bottom → r_top(即B列,当c_left=0时)
7.3 角点共享规则
左上角 (c_left, r_top) = 上边起点 = 左边终点 → Pin 1
右上角 (c_right, r_top) = 上边终点 = 右边起点
右下角 (c_right, r_bottom) = 右边终点 = 下边起点
左下角 (c_left, r_bottom) = 下边终点 = 左边终点
总Pin数 = 2 × width + 2 × height - 4
7.4 长方形支持
非正方形示例:width=6, height=4
总Pin数 = 2×6 + 2×4 - 4 = 16
上边:6个引脚(1-6)
右边:3个引脚(7-9)
下边:5个引脚(10-14)
左边:3个引脚(15-16,回到Pin 1)
验证:6 + 3 + 5 + 2 = 16 ✓(左边排除两个角点)
8. 任务拆分建议
8.1 推荐拆分方案
建议拆分为 3 个子任务,由 2-3 个编码 Agent 并行开发:
任务 A:Excel 读写引擎(最复杂,优先开发)
负责模块:xls_reader.py, xlsx_reader.py, xlsx_writer.py
工作内容:
- 实现 BIFF8 OLE2 解析器(xls 读取)
- 实现 ZIP+XML 解析器(xlsx 读取)
- 实现 OOXML 生成器(xlsx 写入)
- 统一接口:
read_excel(filepath) → dict[(row,col), str] - 编写单元测试(用已知 xls/xlsx 文件验证)
预估工作量:高(BIFF8 解析是最大难点)
关键风险:
- BIFF8 变体多(BIFF5/BIFF8 混用、不同 Unicode 编码)
- 需要大量测试文件验证
任务 B:PinMAP 解析与验证(核心业务逻辑)
负责模块:pinmap_parser.py, validator.py
工作内容:
- 实现方形边界检测算法
- 实现四边引脚提取逻辑
- 实现角点共享处理
- 实现验证规则(连续性、唯一性、完整性)
- 编写单元测试(模拟各种 PinMAP 布局)
预估工作量:中
关键风险:
- 边界条件处理(长方形 vs 正方形、最小尺寸)
- 角点共享逻辑的正确性
任务 C:流程编排与输出(集成层)
负责模块:main.py, file_selector.py, pinlist_generator.py
工作内容:
- 实现文件选择对话框
- 实现 PinList 数据转换
- 实现输出文件命名和保存
- 实现主流程异常处理和用户提示
- 端到端集成测试
预估工作量:低
关键风险:
- tkinter 在 Windows 上的兼容性
- 用户交互流程的友好性
8.2 开发顺序
第1轮:任务 A(Excel 读写引擎)
↓ 完成后
第2轮:任务 B(PinMAP 解析与验证)
↓ 完成后
第3轮:任务 C(流程编排与输出)
↓ 完成后
集成测试 → 发布
8.3 接口契约(模块间约定)
# xls_reader / xlsx_reader 统一接口
def read_excel_cells(filepath: str) -> dict[tuple[int, int], str]:
"""
输入: Excel 文件路径
输出: {(row, col): str} 单元格字典
约定: row/col 从 0 开始,所有值转为 str
"""
# pinmap_parser 接口
def parse_pinmap(cells: dict[tuple[int, int], str]) -> PinMAP:
"""
输入: 单元格字典
输出: PinMAP 对象
约定: 结构错误时抛出 StructureError
"""
# validator 接口
def validate_pinmap(pinmap: PinMAP) -> ValidationResult:
"""
输入: PinMAP 对象
输出: ValidationResult
约定: 不抛出异常,所有问题记录在 ValidationResult 中
"""
# pinlist_generator 接口
def generate_pinlist(pinmap: PinMAP, validation: ValidationResult) -> PinList:
"""
输入: PinMAP + ValidationResult
输出: PinList 对象
约定: 自动处理 WARN 级别的缺失 PinName(设为 NC)
"""
# xlsx_writer 接口
def write_pinlist_xlsx(pinlist: PinList, output_path: str):
"""
输入: PinList + 输出路径
输出: 无(写入文件)
约定: 自动创建父目录
"""
9. 项目目录结构
pinmap-to-pinlist/
├── Code/
│ ├── src/
│ │ ├── __init__.py
│ │ ├── main.py # 入口点
│ │ ├── file_selector.py # 文件选择
│ │ ├── xls_reader.py # XLS 读取引擎
│ │ ├── xlsx_reader.py # XLSX 读取引擎
│ │ ├── pinmap_parser.py # PinMAP 解析
│ │ ├── validator.py # 数据验证
│ │ ├── pinlist_generator.py # PinList 生成
│ │ ├── xlsx_writer.py # XLSX 写入引擎
│ │ └── models.py # 数据模型定义
│ └── docs/
│ └── architecture-design.md # 本文档
├── Test/
│ ├── fixtures/ # 测试用 Excel 文件
│ │ ├── sample_4x4.xls
│ │ ├── sample_4x4.xlsx
│ │ ├── sample_rect.xls
│ │ └── ...
│ └── test_*.py # 单元测试
└── Releases/
└── pinmap2pinlist.exe # 打包后的可执行文件
10. 风险与缓解
| 风险 | 影响 | 概率 | 缓解措施 |
|---|---|---|---|
| BIFF8 格式变体导致解析失败 | 高 | 中 | 收集多种 xls 样本测试;优先实现 BIFF8 最常见子集 |
| tkinter 在无头环境不可用 | 中 | 低 | 回退到命令行参数模式 |
| xlsx 写入的 XML 结构不兼容老版本 Excel | 中 | 低 | 遵循 OOXML 标准,使用最小兼容集 |
| 超大文件(>1000引脚)性能问题 | 低 | 低 | 当前场景引脚数通常 <100,无需优化 |
11. 附录
A. BIFF8 记录类型速查
| 记录码 | 名称 | 说明 |
|---|---|---|
| 0x0009 | BOF | 块起始 |
| 0x000A | EOF | 文件结束 |
| 0x00FD | LABELSST | 共享字符串表引用单元格 |
| 0x0203 | NUMBER | 浮点数单元格 |
| 0x0006 | FORMULA | 公式单元格 |
| 0x000C | RK | RK 数值 |
| 0x00FC | STRING | 公式字符串结果 |
| 0x0034 | SST | 全局共享字符串表 |
| 0x0042 | BOUNDSHEET | 工作表信息 |
| 0x00E0 | EXTSST | 扩展共享字符串表 |
B. OOXML xlsx 目录结构
example.xlsx (ZIP)
├── [Content_Types].xml
├── _rels/
│ └── .rels
├── xl/
│ ├── workbook.xml
│ ├── _rels/
│ │ └── workbook.xml.rels
│ ├── sharedStrings.xml
│ ├── styles.xml
│ └── worksheets/
│ ├── sheet1.xml
│ └── sheet2.xml
└── docProps/
├── core.xml
└── app.xml
C. 列字母 ↔ 索引转换
def col_letter_to_index(letter: str) -> int:
"""A→0, B→1, ..., Z→25, AA→26, AB→27, ..."""
result = 0
for ch in letter.upper():
result = result * 26 + (ord(ch) - ord('A') + 1)
return result - 1
def col_index_to_letter(index: int) -> str:
"""0→A, 1→B, ..., 25→Z, 26→AA, ..."""
result = ""
index += 1
while index > 0:
index -= 1
result = chr(index % 26 + ord('A')) + result
index //= 26
return result
文档结束 — 请审批后进入编码阶段