Files
skills/file-reader/SKILL.md
T
hmo 04db423416 Initial commit: skills library
- 70 skills with code and documentation
- Add .gitignore (ignore __pycache__, output/, temp/, venv/)
- Clean up test intermediates and caches
2026-04-26 19:27:40 +08:00

12 KiB
Raw Blame History

name, description
name description
file-reader 文件读写编辑技能。读取、创建、编辑 docx/xlsx/pdf/pptx 等文件,特别处理中文编码问题。

文件读写编辑技能

概述

支持对 Word、Excel、PDF、PPT 四类办公文档进行读取、创建、编辑操作。 特别针对 WPS/Office 创建的中文文档编码问题提供解决方案。

适用场景

  • 读取 .docx / .xlsx / .pdf / .pptx 文件内容
  • 创建新的办公文档(报告、表格、演示文稿、PDF)
  • 编辑已有文档(修改内容、格式、公式等)
  • 中文编码乱码问题处理
  • PDF 合并/拆分/OCR/加水印
  • Excel 公式模型构建

一、Word 文档(docx

1.1 读取

# 使用内置脚本(自动处理中文编码)
python .opencode/skills/file-reader/scripts/file_reader.py <file.docx>

内容保存到 temp/docx_output.txt,确保中文在 Windows 终端也能正确查看。

中文编码原理WPS 创建的 docx 内部 XML 可能是 GBK 编码但声明为 UTF-8,直接用 python-docx 会乱码。脚本直接从 zip 包读取 XML 并正确处理编码。

1.2 创建新文档

使用 docx-jsNode.js)生成,安装:npm install -g docx

const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell,
        ImageRun, Header, Footer, AlignmentType, HeadingLevel, BorderStyle,
        WidthType, ShadingType, PageNumber, PageBreak, LevelFormat,
        TableOfContents, PageOrientation } = require('docx');
const fs = require('fs');

const doc = new Document({
  styles: {
    default: { document: { run: { font: "Arial", size: 24 } } }, // 12pt
    paragraphStyles: [
      { id: "Heading1", name: "Heading 1", basedOn: "Normal", next: "Normal",
        quickFormat: true,
        run: { size: 32, bold: true, font: "Arial" },
        paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0 } },
    ]
  },
  sections: [{
    properties: {
      page: {
        size: { width: 12240, height: 15840 }, // US Letter (DXA单位, 1440=1英寸)
        margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 }
      }
    },
    children: [/* 内容 */]
  }]
});

Packer.toBuffer(doc).then(buf => fs.writeFileSync("output.docx", buf));

关键规则

  • 页面尺寸必须显式设置(默认 A4,US Letter 需指定 12240x15840
  • 横向:传纵向尺寸 + orientation: PageOrientation.LANDSCAPE(内部自动交换)
  • 禁止用 \n 换行,用多个 Paragraph
  • 禁止用 Unicode 项目符号,用 LevelFormat.BULLET + numbering config
  • PageBreak 必须放在 Paragraph
  • ImageRun 必须指定 typepng/jpg 等)
  • 表格必须同时设置 columnWidths 和每个 cell 的 width,且用 WidthType.DXA(百分比在 Google Docs 会坏)
  • 表格着色用 ShadingType.CLEAR(不是 SOLID,否则全黑)
  • 目录 TOC 要求标题用 HeadingLevel,且样式中包含 outlineLevel

1.3 编辑已有文档

采用 XML 解包→编辑→重打包 三步法:

# 步骤1:解包
python scripts/office/unpack.py document.docx unpacked/

# 步骤2:编辑 unpacked/word/ 下的 XML 文件
# 直接用 Edit 工具做字符串替换,不要写 Python 脚本

# 步骤3:重打包
python scripts/office/pack.py unpacked/ output.docx --original document.docx

修订标记(Tracked Changes

<!-- 插入 -->
<w:ins w:id="1" w:author="Claude" w:date="2025-01-01T00:00:00Z">
  <w:r><w:t>新文本</w:t></w:r>
</w:ins>

<!-- 删除(注意用 delText 不是 t -->
<w:del w:id="2" w:author="Claude" w:date="2025-01-01T00:00:00Z">
  <w:r><w:delText>被删文本</w:delText></w:r>
</w:del>

注意事项

  • 替换整个 <w:r> 元素,不要在 run 内部插入修订标签
  • 保留原始 <w:rPr> 格式块
  • 新内容中的引号用 XML 实体:&#x201C;"&#x201D;"&#x2019;'
  • 删除整段时需在 <w:pPr><w:rPr> 中也加 <w:del/>,否则接受修订后留空段

二、PDF 文档(pdf

2.1 读取

# 使用 pypdf 读取并保存到文件(避免终端中文乱码)
python -c "
from pypdf import PdfReader
r = PdfReader('<file.pdf>')
with open('temp/pdf_output.txt', 'w', encoding='utf-8') as f:
    for i, p in enumerate(r.pages):
        f.write(f'--- Page {i+1} ---\n')
        f.write(p.extract_text() + '\n\n')
"

提取表格pdfplumber 更强):

import pdfplumber
with pdfplumber.open("doc.pdf") as pdf:
    for page in pdf.pages:
        tables = page.extract_tables()
        for table in tables:
            for row in table:
                print(row)

2.2 合并与拆分

from pypdf import PdfReader, PdfWriter

# 合并多个 PDF
writer = PdfWriter()
for f in ["doc1.pdf", "doc2.pdf"]:
    for page in PdfReader(f).pages:
        writer.add_page(page)
with open("merged.pdf", "wb") as out:
    writer.write(out)

# 拆分为单页
reader = PdfReader("input.pdf")
for i, page in enumerate(reader.pages):
    w = PdfWriter()
    w.add_page(page)
    with open(f"page_{i+1}.pdf", "wb") as out:
        w.write(out)

2.3 创建新 PDF

使用 reportlab

from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak
from reportlab.lib.styles import getSampleStyleSheet

doc = SimpleDocTemplate("report.pdf", pagesize=letter)
styles = getSampleStyleSheet()
story = [
    Paragraph("报告标题", styles['Title']),
    Spacer(1, 12),
    Paragraph("正文内容..." * 20, styles['Normal']),
    PageBreak(),
    Paragraph("第二页", styles['Heading1']),
]
doc.build(story)

陷阱:禁止在 reportlab 中使用 Unicode 上下标字符(₀₁₂ ⁰¹²),内置字体不支持会渲染成黑块。用 <sub> <super> 标签代替。

2.4 OCR 扫描件

# 依赖:pip install pytesseract pdf2image
import pytesseract
from pdf2image import convert_from_path

images = convert_from_path('scanned.pdf')
for i, img in enumerate(images):
    text = pytesseract.image_to_string(img, lang='chi_sim')  # 中文用 chi_sim
    print(f"Page {i+1}:\n{text}\n")

2.5 其他操作

from pypdf import PdfReader, PdfWriter

# 旋转页面
page = PdfReader("input.pdf").pages[0]
page.rotate(90)

# 添加水印
watermark = PdfReader("watermark.pdf").pages[0]
for page in PdfReader("doc.pdf").pages:
    page.merge_page(watermark)

# 加密
writer.encrypt("user_password", "owner_password")

命令行工具

pdftotext -layout input.pdf output.txt     # 提取文本(保留布局)
qpdf --empty --pages f1.pdf f2.pdf -- out.pdf  # 合并
pdfimages -j input.pdf prefix               # 提取图片

三、PPT 演示文稿(pptx

3.1 读取

# 文本提取
python -m markitdown presentation.pptx

# 缩略图预览
python scripts/thumbnail.py presentation.pptx

# 原始 XML
python scripts/office/unpack.py presentation.pptx unpacked/

3.2 创建新演示文稿

使用 pptxgenjsNode.js),安装:npm install -g pptxgenjs

无模板时从头创建,有模板时用解包→编辑→打包流程。

3.3 编辑已有文件

# 1. 分析模板
python scripts/thumbnail.py presentation.pptx

# 2. 解包→编辑→打包
python scripts/office/unpack.py presentation.pptx unpacked/
# 编辑 XML...
python scripts/office/pack.py unpacked/ output.pptx --original presentation.pptx

3.4 设计规范

配色:不要默认蓝色,根据主题选择配色方案。深色背景用于首尾页,浅色用于内容页。

字体搭配(标题/正文):Georgia+Calibri、Arial Black+Arial、Cambria+Calibri

字号规范

元素 字号
幻灯片标题 36-44pt 加粗
章节标题 20-24pt 加粗
正文 14-16pt
注释 10-12pt

常见错误

  • 不要重复相同布局,要变换排版
  • 正文左对齐,仅标题居中
  • 每页必须有视觉元素(图、图标、图表),拒绝纯文字幻灯片
  • 禁止标题下划线(AI 生成痕迹明显)
  • 设置 text box margin: 0 或偏移以对齐装饰线与文字边缘

3.5 QA 检查(必须执行)

# 内容检查
python -m markitdown output.pptx

# 视觉检查:转图片后逐页审查
python scripts/office/soffice.py --headless --convert-to pdf output.pptx
pdftoppm -jpeg -r 150 output.pdf slide

# 检查残留占位符
python -m markitdown output.pptx | grep -iE "xxxx|lorem|ipsum"

检查清单:元素重叠、文字溢出、间距不均、低对比度、占位符残留。 至少完成一轮 修复→验证 循环才能交付。


四、Excel 电子表格(xlsx

4.1 读取

# 使用内置脚本(自动处理中文编码)
python .opencode/skills/file-reader/scripts/file_reader.py <file.xlsx>             # 列出所有sheets
python .opencode/skills/file-reader/scripts/file_reader.py <file.xlsx> <sheet_idx>  # 读指定sheet(默认前20行)
python .opencode/skills/file-reader/scripts/file_reader.py <file.xlsx> <sheet_idx> <max_rows>  # 指定行数

中文编码原理:直接读取 xlsx 内部 XMLsharedStrings.xml),使用 UTF-8 解码,绕过 openpyxl 可能的编码问题。

pandas 分析

import pandas as pd
df = pd.read_excel('file.xlsx')                          # 默认第一个sheet
all_sheets = pd.read_excel('file.xlsx', sheet_name=None) # 所有sheet
df.describe()                                             # 统计摘要

4.2 创建与编辑

from openpyxl import Workbook, load_workbook
from openpyxl.styles import Font, PatternFill, Alignment

# 创建新文件
wb = Workbook()
ws = wb.active
ws['A1'] = '标题'
ws['A1'].font = Font(bold=True, size=14)
ws.column_dimensions['A'].width = 20

# 编辑已有文件
wb = load_workbook('existing.xlsx')
ws = wb['Sheet1']
ws['B2'] = '=SUM(B3:B10)'

wb.save('output.xlsx')

4.3 公式规范(铁律)

必须用 Excel 公式,禁止在 Python 中算好再硬编码到单元格!

# ❌ 错误:Python 计算后写死值
total = df['Sales'].sum()
sheet['B10'] = total  # 写死 5000

# ✅ 正确:写 Excel 公式
sheet['B10'] = '=SUM(B2:B9)'
sheet['C5'] = '=(C4-C2)/C2'
sheet['D20'] = '=AVERAGE(D2:D19)'

公式写入后必须重新计算:

python scripts/recalc.py output.xlsx

脚本返回 JSON,如果 statuserrors_found,根据 error_summary 修复后重新计算。

4.4 财务模型规范

颜色编码

  • 蓝色文字 (0,0,255):硬编码输入值
  • 黑色文字 (0,0,0):公式和计算
  • 绿色文字 (0,128,0):跨 sheet 引用
  • 红色文字 (255,0,0):外部文件链接
  • 黄色背景 (255,255,0):关键假设

数字格式

  • 年份格式化为文本(避免 2024 变成 2,024)
  • 货币用 $#,##0,标题注明单位
  • 零值显示为 -
  • 负数用括号 (123) 不用减号
  • 百分比默认 0.0%

4.5 注意事项

  • openpyxl 单元格索引从 1 开始
  • data_only=True 读取计算值,但保存后公式会永久丢失
  • pandas 读取时指定 dtype={'id': str} 避免类型推断问题
  • 假设值放单独单元格,公式用引用,不要内嵌常量
  • 跨 sheet 引用格式:Sheet1!A1
  • 检查公式错误:#REF!#DIV/0!#VALUE!#NAME?

五、中文编码问题总结

文件类型 问题根源 解决方案
xlsx WPS 内部 XML 可能是 GBK 但声明 UTF-8 直接读 zip 内 XML,正确解码
docx 同上 直接读 word/document.xml,尝试 UTF-8/GBK
pdf 提取的中文在 Windows 终端乱码 保存到 UTF-8 文件再读取
pptx 类似 docx 用 markitdown 或解包 XML

六、依赖安装

# Python 核心(读取)
pip install python-docx openpyxl pypdf pdfplumber

# PDF 创建与 OCR
pip install reportlab pytesseract pdf2image

# PPT 文本提取
pip install "markitdown[pptx]" Pillow

# Node.js(文档创建)
npm install -g docx        # Word 创建
npm install -g pptxgenjs   # PPT 创建

# 系统工具(可选)
# LibreOffice - PDF转换、公式重算
# Poppler (pdftoppm/pdftotext/pdfimages) - PDF处理
# Tesseract - OCR

七、输出文件位置

文件类型 默认输出路径
xlsx 读取 temp/xlsx_output.txt
docx 读取 temp/docx_output.txt
pdf 读取 temp/pdf_output.txt

保存到文件是为了确保中文在 Windows 终端乱码时仍可正确查看。