学习通题库导入 · XLS 生成

SKILL教育学习
教育学习 未标注权限 许可证不明确
安装这个技能

把「试卷 docx + 答案 docx」按超星学习通题库导入模板转成可上传的 .xls,并逐题校验。

一句话选型结论

按资料字段整理

学习通题库导入 · XLS 生成是教育学习类的 Agent Skill,安装方式未标注,权限级别未标注,许可证不明确,有可直接复制的安装命令。技能本质是给模型读的说明书,效果取决于模型与客户端;装完先用一个小任务验证,再放进正式流程。

分类教育学习 安装方式未标注 权限级别未标注权限 许可证许可证不明确
累计安装 未标注 本周 未标注
GitHub 星标 未标注 仓库 未标注
下载量 未标注 技能市场下载数
权限级别 未标注权限 安装前请确认风险范围
许可证 许可证不明确 未说明

安装

未标注
在支持 Skills 的客户端里执行,装完问一句「你有哪些技能」验证
skillhub install user_3853b7f7/xuetang-question-bank-import
  1. 1
    确认客户端支持

    确认你的客户端支持 Skills(Claude、Codex、Cursor 等),并升级到较新的版本。

  2. 2
    拿到技能文件

    执行上面的命令安装;也可以把仓库里的 SKILL.md 手动放进客户端的 skills 目录。

  3. 3
    刷新技能列表

    重新打开客户端,或刷新技能列表,让新放进来的技能被加载。

  4. 4
    验证是否生效

    问一句「你有哪些技能」,确认列表里出现它,再拿一个小任务试跑。

技能档案

教育学习
字段来自技能仓库与公开索引,中文说明由本站标注
作者 / 维护方user_3853b7f7仓库 未标注 · 版本 未标注
宿主客户端未标注技能可被这些客户端加载
安装方式未标注安装包 community
权限级别未标注权限安装前请确认风险范围
许可证未说明许可证不明确,商用前请自行确认条款
仓库可用性available技能仓库当前是否可访问
最近核验未标注上游最后核验时间 · 数据更新 1791708423
正文体量54.4 KBSKILL.md 原文大小,越大说明说明书写得越细

典型使用场景

3 类
按分类整理的常见用法,具体以 SKILL.md 为准
讲解知识点

按水平把知识点讲清楚。

出练习题

按章节生成练习与答案。

制定学习计划

按目标和时间排学习节奏。

选择建议

装之前先看这几条
按条目字段给出的判断,不替你决定用不用

值得选的地方

  • 有可直接复制的安装命令,不用自己翻文档找入口。

先想清楚的地方

  • 没有标注权限级别,实际能做什么要装好后确认。
  • 许可证不明确,商用或二次分发前先到仓库确认条款。
  • 没有做站内核验,内容以作者仓库为准。
  • 技能只是说明书,实际效果取决于模型与客户端,装完先用小任务试一遍。

更适合

  • 需要在教育学习场景里给模型补一套做法的人。
  • 愿意先读一遍 SKILL.md、确认它会让模型做什么的人。

不太适合

  • 对许可证要求很严、必须明确可商用的人。
  • 只想装完就自动变强、不打算看说明书的人。

同类对比

6 个同类
同分类里挑最接近的几条,字段以各自详情页为准
技能权限级别安装方式累计安装宿主客户端安装命令
学习通题库导入 · XLS 生成当前 未标注权限 未标注 未标注 未标注 有
食谱创建课堂课程 未标注权限 GitHub 仓库 25.5 万 Codex、Claude、Cursor 有
语言学习 联网访问 ClawHub 市场 23.6 万 OpenClaw 有
learning 效率 只读 ClawHub 市场 19.2 万 OpenClaw 有
学习习惯 未标注权限 ClawHub 市场 10.2 万 OpenClaw 有
日语家教 只读 ClawHub 市场 8.2 万 OpenClaw 有

SKILL.md 全文

54.4 KB
模型实际读到的说明书原文,来自技能仓库

学习通题库导入 · XLS 生成(手册 v4)

> 本手册由本项目多轮「生成 → 平台导入 → 报错 → 定位 → 修复 → 再验证」的实测沉淀而成,覆盖 8 档约 1 万道题。
> 所有规则都是平台实测结论,不是推测。凡标注「⚠️」的为会导致导入失败或静默丢题的高危项。
> 版本:手册 v4 ≡ 包版本 v1.2.0(发布包 xuetang-question-bank-import_v1.2.0.zip;frontmatter version 与本文「手册 vN」一一对应,改动一处必须同步另一处)。
> 手册 v4 内容(2026-09-25 深夜,补 A18「删备份前先 grep 谁在读它」+ A19「备份四种定性」,A17 补一次实例;主干:补 A17 清理类「假绿」陷阱;新增:题干出处/版权/水印残留自动清洗 strip_source_tags()、答案文档自动配对比对(verify 第 24 项)、平台题量口径(大题数)、selftest_neg.py 反向自测)


0. 铁律速查(开工前 60 秒读完)

# 铁律 违反后果
1 简单题(单选/简答/填空)的题干写「大题题干」列,「小题题型/小题题干」两列留空 ⚠️ 整批静默丢弃,平台不报错(2026-09-24 初中 1000 道单选全丢)
2 只填自己会填的字段,平台会补的一律不写:选项列不带 A.、题干不带题号 显示成 A.A. xxx / 43) xxx
3 选项正文前必须补 1 个 NBSP(U+00A0)(填空题/简答题的答案列除外) 显示成 A.正文(无间距)
4 非完型填空的题干里 ## 必须为 0,空位一律写 ______ 导入卡死在「正在识别 90%」
5 组合题大题行的题型写错、小题题型写 完型填空 整组拒收
6 目录列归一(无 /xx英语/ 之类旧前缀残留),全表统一一个根 目录被拆成两棵
7 单次导入文件 ≤ 999 题;组合题文件重导前先删平台旧目录 超限卡死 / 组合题重复叠加
8 平台只对简单题去重,组合题不去重 → 导入前必须自己做「单元原子级」去重 组合题翻倍入库
9 宁缺勿错:答案不可信就整题/整篇剔除,不猜、不编 错答案进库 = 教学事故
10 任何新增加工列,必须同步补一条交付前断言 漏一条 = 一次上传被拒

1. 触发场景与支持的题源类型

1.1 何时调用本 skill

触发信号 说明
用户给出《XX 单元测试题》+《答案》+ importQuestionTemplateNew(题库导入模板).xls,要求生成可上传学习通的题库文件 最典型场景
用户说「把这份试卷做成题库」「导入学习通题库」「按模板填题」「转成超星题库」 同义表述
用户上传导入失败数据 zip(question_import_error.xlsx)要求排查 走第 5 章报错表
用户报「某题型一题都没导进去」 先查铁律 1(简单题布局),再查其余
已有题库需要按教学档位/层次分批导出分包 走 S8 分包 + 目录归一

不适用场景(必须先转述给用户):
- 需要音频列——学习通导入模板无音频列,听力题只能导入后在题目编辑页手动挂接。
- 需要图片选项——图片二进制不能塞 XLS,只能写占位并在报告里列「需人工补图」清单。

1.2 支持的题源类型与解析通道

题源 解析方式 关键风险与要点
Word (.docx) python-docx,必须保序读(正文段落与表格交替,用 iter_block_items) ① 图片选项读不到 → 需 scan_images.py;② 文本框(txbxContent) 常藏选项库/选词库 → 需 dump_textbox.py
Word (.doc) 本机 WPS COM 转换(见用户级记忆《.doc 文件》条目) 不要走云端转换
Excel (.xls/.xlsx) 已有题库 xlrd 读 最直接——直接当"二级题源",但仍要走第 2 章清洗
纯文本 / txt 正则切分 空位形态多源不一,需按空位归一规则统一
OCR 图片 / 扫描 PDF rapidocr_onnxruntime(离线,脚本 jpg_ocr.py) OCR 会把行内编号误认、数字粘连(30→3O)、正文印两遍;详见附录 B 大编号题源节
网页真题 直连下载原始 HTML/PDF(_net_fetch_*.py) ⚠️ 超长汇编页必然被截断;正文取到但答案键被截断 ⇒ 该页不可作答案源
平台导入失败数据 zip 解压读 question_import_error.xlsx 报错不指题号,只能反查本地

2. 输入规范:格式要求、预处理与清洗

2.1 题源材料的最低格式要求

要求 说明
「题目」与「答案」分离 答案文档常按 1)-5) BABCA 紧凑格式给,需展开成 {题号: 答案}
题号可定位 每道题要有形如 1. / (1) / 1) 的行首编号(切题正则依赖它)
题干与选项同行或同段 若选项跨段散落,需人工归并
材料编码 UTF-8/GBK 均可 读到后统一 html.unescape() 解码 HTML 实体、统一全半角标点
答案可核验 不允许"凭记忆补全"答案;某篇没有可靠答案键就整篇剔除

2.2 预处理清洗规则(在切题之前一次性做完)

序 清洗项 规则 命中的典型病例
C1 HTML 实体解码 html.unescape(),题干与选项都要 don't、she's
C2 控制字符清除 替换 \x01 等控制符为空位 ______ 历史抓取残留,每格 1–4 个
C3 出处标注剥离 【[^】]{1,30}】(上限放宽到 30,旧 {1,10} 会漏剥) 【NMET全国IV-32】、选项尾部 【NMET】
C4 题号前缀剥离(只剥行首一层) ^\s*[\((]?\s*\d{1,3}\s*[\))\..、::]\s*(?![0-9]) 43) I learned…;(?![0-9]) 用于放行 2.5 million
C5 选项字母前缀剥离 只留正文,去掉 A. / B、 / (A) 平台会自己补字母,重复补会显示 A.A.
C6 空位归一 只认两类空位:① 连续下划线(_ 与全角 _);② 行内连续半角空格 {2,}(不含制表符、不含行首缩进全角空格) 版式对齐 satisfactory \t\texp、会话破折号 ----Have you seen 都不是空位
C7 多解分隔归一 which/that、is/was → 统一写 ; 平台只认 ;
C8 全半角标点归一 逗号 ,→,、冒号→: 等(仅用于匹配键归一化,不改答案内容) 全角逗号导致匹配失配
C9 段落保序 docx 用 iter_block_items;网页抓取逐段落盘 保序是「大题材料 + 小题题干」对齐的前提
C10 先落盘原则 正文一旦解析出来,无论有没有答案,先存盘(哪怕是 _pending_answer.json) 实测:没答案就不存,答案补回来时正文也丢了,14 篇只能重抓

2.3 答案材料的预处理

官方《答案》文档是给人看的排版,val.parse_answers 只认三种形态:

  • 1-5 BACBC(区间 + 纯字母)
  • 1-5 a; b; c(区间 + 分号拆分)
  • 1) B 2) C(同行多题)

必须先跑「只改排版、不改内容」的规范化脚本,产出 {KEY}_ans2.txt 再比对。典型病态行与补丁见附录 B 第 8 步表。

两条口径红线:
- XLS 交付用 ;,校验对照文档用空格(val.norm 会把 ; 拆成 2 个单元,口径错位会报「答案序列不一致」)。
- 规范化只做:补题号、拆行、逗号/空格→分号、删行标。任何答案内容改动都是红线。


3. 执行流程(S1–S10,严格按序)

S1 · 核对模板(不可跳过)

读模板第 1 行表头 + 第 2 行说明行,确认 20 列字段与顺序。不同版本模板列数可能不同,不许凭记忆写死。

  • 模板第 2 行「导入前请删除此行」必须移除(导入器不会自动跳)。
  • 模板自带示例行(如纯文本 作者是赵崇祚)就是「不带字母前缀」的基准,照它写。

S2 · 解析题源

按第 1.2 表选通道。docx 用保序读取;xls 用 xlrd;网页直连下载;OCR 走离线引擎。

> ⚠️ 写校验脚本前先 dump 前 6 行逐列打印(列号 + 表头 + 值)确认真实列映射,再写统计。
> 常见错法:「按 B 列是否为空区分大题/小题」——大题行 A/B 都填、小题行 A/B 都空,判定小题应用 B=='' and E!='';取答案本体用 M 列(不是 G 列)。

S3 · 题目切分

场景 切分依据
常规 行首题号正则 (?m)^\s*[#\*]*\s*(\d{1,3})\s*[..、]
大编号题源(空位全局连续编号 1..N) 不要依赖「阅读下面短文…」分隔句(常缺失)。改用「空位编号按每篇空数自然成组」的全局不变量:n % PER == 1 即新篇起点
OCR 编号粘连 30→3O、1O 等,容许切题正则前置 #/*;选项清洗时截断污染信号 \s+\d{1,3}\s*[Oo0]\s*\.
官方答案单元数 ≠ 卷面题号数 以答案单元数为准重排录入(如 Questions 1–2 (4 points) 实含 4 段对话 → 按 4 题录)

自检:题号 1..N 连续无缺漏、无重号。

S4 · 题型归一(映射表)

原卷板块 归一题型 结构
听力选择 / 语法选择 / 词汇结构 单选题 独立题,选项 A–D
完形填空(短文 M 空 × 每空 4 选 1) 完型填空 1 大题行(##1##…##M##)+ M 小题行
阅读理解(短文 + 选择) 阅读理解 1 大题行(短文)+ N 小题行(小题题型=单选题)
补全对话(N 选项选 M 空) 共用选项题 1 大题行(含共用选项)+ M 小题行
选词填空 / 段落匹配(A–O 十五词) 阅读理解型组合题 大题 = 整篇(空缺按真题原位保留 26 ______ + 词库原文)+ N 个填空题小题(填词)。⚠️ 材料里绝不能出现 ##n##
选词填空(无词库) 同上,词库取自官方【词性分析】词表,并在报告写映射表 必须在报告注明来源
语法填空(1 篇 N 空) 完型填空 / 语法填空组 1 大题 + N 填空小题(视平台小题题型支持度选)
听短文填空 / 句子填空 填空题 1 行,题干含 N 个空,答案 = 字母序列
翻译(英译汉 / 汉译英段落) 简答题 正确答案 A;选项A = 参考译文;解析 = 采分点;选项数 = 1
命题作文 简答题 正确答案 A;选项A = 参考范文;解析 = 评分维度
「勾选」二选一 / 表格内 √Yes/√No 填空题(1 空) 把正确项文本放进选项A
A 栏配 B 栏(连线/匹配 5 对) ⚠️ 模板只有 A–H 八列,5+5 放不下 → 须拆解或改方案 不要硬塞、不要丢选项

> 遇到模板未覆盖或用户未明确的映射,先问用户,不要自创题型。

S5 · 字段提取与填列

按第 4 章的 20 列表逐个填。要点:

  1. 独立题(单选/简答/填空):题干 → D 列;E/F 列留空。
  2. 组合题大题行:题型 → B 列;材料 → D 列;除 A/B/D/I/J/K 外全部留空(含 col2 自定义题型、col4 小题题型必须清空)。
  3. 组合题小题行:A(目录)与 B(题目类型)留空;填 E 小题题型 / F 小题题干 / G 正确答案 / L 选项数 / M–T 选项。
  4. 完形填空小题行不填「小题题干」,空位靠大题题干里的 ##n## 标记。
  5. 组合题「填空题」小题的「正确答案」必须填选项列字母序列(单空 = A),答案本体写进「选项A」。
    (把真题词库字母 G / 段落字母 K 直接填进「正确答案」= 引用一个不存在的选项 → 越界。)
  6. 简答/翻译/写作的答案与范文只能写进「选项A」,绝不能写进「答案解析」(会印到学生卷面上)。

S6 · 清洗与布局修复(自动化钩子)

在写文件时依次调用,顺序不可换:

regroup_xuanci → normalize → fix_cloze_markers → fill_cloze_substems
  → fix_simple_layout → strip_source_tags → fix_subjective_answer
  → pad_substem_opts → dedup_units → assert_clean

> ⚠️ 顺序铁律:strip_source_tags 必须在 dedup_units 之前——同题双份入库的副本往往只差一个水印/出处标注,不先清洗就判重会漏掉全部克隆。2026-09-25 实测:清洗前 16 件全绿,清洗后立刻暴露 14 行隐藏重复。

S6-a 简单题布局归位 fix_simple_layout()(2026-09-24 新增,最高优先级)

分支 判据 动作
A. 题干归位 题目类型==单选题 且 D 列为空/占位(如 单选题)而 F 列有真题干 row[3], row[5] = row[5], ""
B. 残留小题题型清理 题目类型==单选题/简答题 且 E 列非空 row[4] = ""
C. 英译汉占位归位 题目类型==简答题 and D 列 in ("英译汉","翻译") and F 列有值 row[3], row[5] = row[5], ""

> ⚠️ 这是本 skill 最贵的一条经验:学习通规定简单题的题干必须在「大题题干」列;把真题干写在「小题题干」列、D 列写占位,解析器会把它判成「声明了小题却没有小题行」的组合题,于是整行静默丢弃、平台不报错、界面只显示题数变少。2026-09-24 初中两分包共 1000 道单选全部消失,排查数轮才定位。

S6-b 组合题小题题型归一 fill_cloze_substems()

  • 小题题型只认『单选题』(学习通支持的词)。写『完型填空』会被判「小题题型为空或不支持」,整组拒收。
  • 该钩子对已有值也要强制归一(只补空值会漏掉 540 行同病)。

S6-c 空位标记 fix_cloze_markers()

  • 完形大题题干空位写成 ##1##…##M##,按下标编号,不用全卷题号。
  • 空位来源格式多源不一:半角/全角空格包数字、数字粘词(not2enough)、编号 16-30 / 46-60 / 61-75。
  • 用「独立数字候选的连续递增子序列唯一命中」算法定位,⚠️ 不能简单 find():正文里 Oct. 11 / 45 / 50 / 95 是真实数字,会被误转。
  • 非完型材料里的空位写成真题印刷形态 26 ______ / ______,不得写 ##n##。

S6-d 控制字符与非法字符:全表断言 \x01 == 0、'##' == 0(完型除外)、''' == 0、'【' == 0、选项内无 ___ / # / &。

S6-e 目录归一:目录列值统一形如 /高中/单项选择。⚠️ 残留 /高中英语/、/高职英语/ 会生成独立公开目录;/初中//初中/ 双前缀会被拼成怪路径。修源库 + 修生成器,两边都要。

S6-f 出处/版权/水印残留清洗 strip_source_tags()(2026-09-25 新增)

只处理题干两列(大题题干 D / 小题题干 F),不动解析列(G 的【评分维度】【词库】是合法标注)。清洗四类,保留三类:

清洗(会印在卷面) 保留(功能/有意标注)
【版权所有:21教育】、【出处:…】 【词库】(选词题词库)
【2024届天津市…一模】、【2019·天津卷】、【2024新课标II卷…】、【…高考真题】 CET 真题样板套次标注【选词填空/仔细阅读·20XX年·第N套】
裸水印:21教育网 / 21cnjy.com / www-2-1-cnjy-com / 2-1-c-n-j-y / 21世纪教育网(www.21cnjy.com) / 中小学教育资源及组卷应用平台 讲义内容本体里的【导语】【答案】【知识巩固】【段首句】
死链接残渣 ( http: / / )、括号版出处(2020高三上·常州期末)等 题干内文的真实引用年份(Mike Shepherd(2011)、The Hidden Life of Trees (2015)、裸 (2022))

> ⚠️ 实测坑:① 不能用「含【】才处理」做短路——裸水印没有【】;② 括号出处必须带出处关键词(届/期末/一模/联考/中学/卷…)才删,否则会误杀内文引用;③ 水印变体极多(21教育网 / 21cnjy / 2-1-c-n-j-y / www-2-1-cnjy-com / 中小学教育资源及组卷应用平台…),全档扫过一轮后必须再扫一轮确认清零。

S7 · 去重(平台视角,必须自己做)

平台行为 结论
简单题 平台按「题干+选项」内容自动去重。内容改了会当新题插入
组合题 平台不去重 → 重复导入一次 = 整批新增

因此导入前必须做单元原子级去重:

COMBO_TYPES = {"完型填空", "阅读理解", "共用选项题", "选做题"}

def row_sig(row):
    """平台视角指纹:只取平台判重相关的列"""
    nrm = lambda x: re.sub(r"\s+", "", str(x)).lower()
    cols = [row[1], row[3], row[4], row[5], row[6]]
    cols += [row[c] for c in range(12, min(29, len(row)))]
    return "\x01".join(nrm(c) for c in cols)

def dedup_units(rows):
    """组合题整单元原子去重;简单题行级去重。返回 (去重后行列表, 丢弃行数)"""
    seen_u, seen_r, out, i = set(), set(), [], 0
    while i < len(rows):
        if str(rows[i][1]).strip() in COMBO_TYPES:
            j = i + 1
            while j < len(rows) and not str(rows[j][1]).strip():
                j += 1                      # 扫到下一个大题行为止 = 一个完整单元
            ukey = "\x02".join(row_sig(r) for r in rows[i:j])
            if ukey not in seen_u:
                seen_u.add(ukey); out.extend(rows[i:j])
            i = j
        else:
            h = row_sig(rows[i])
            if h not in seen_r:
                seen_r.add(h); out.append(rows[i])
            i += 1
    return out, len(rows) - len(out)

> ⚠️ 行级去重会截断组合题:小题行被 fill_cloze_substems 清空小题题干后,兄弟小题指纹可能碰撞 → 跨组误删,一组只留 2/9/1/6 个小题而不报错。必须整单元判等。
> ⚠️ 指纹不能包含目录/标签/知识点/难度/解析——否则克隆题(仅这些列不同)漏放,被平台过滤掉反而丢题。

补充判重:跨批次并入同一题库时,除 id 判重外再加「正文前缀指纹」re.sub(r"[^a-z]","",p.lower())[:120],并用 difflib.SequenceMatcher(...) > 0.85 做模糊兜底(实测漏检过 Jenifer / Jennifer 差一个字母的同篇)。断言:len({key(e["passage"]) for e in items}) == len(items)。

S8 · 切分包

  • 单文件 ≤ 999 题(平台硬限 1000,取 999 留余量)。
  • 优先按「目录 / 题型维度」切,好处是各分包目录列一致,导入后自动归并到同一目录树。
  • 题量 = 独立题数 + 组合题组数(组合题整组只算 1 题,其下辖小题不单独计数)。
  • 交付时主动分成多个文件并逐个标注题数,不给一个超限单文件。

S9 · 写出 .xls(五步原子写,缺一步不得收工)

  • 用 xlwt 写 .xls(与模板同格式);读用 xlrd。装包:pip install xlwt -i https://pypi.tuna.tsinghua.edu.cn/simple
  • sheet 名固定 Sheet1;单元格内换行用 \n 并设 alignment.wrap=1
  • 不要合并单元格、不要超链接、不要公式
  • 目标目录名:学习通题库导入分包的命名规范 见第 4.4 节

> ⚠️ Workbook() 新建 + save() = 整表覆写,不是「追加」。补源/改库时若直接
> wb = xlwt.Workbook(); ...; wb.save(Path),原库会被整表冲掉,只剩本次写进去的
> 内容,且不报错(2026-09-25 事故:高职阅读真源 100 单元/500 小题被冲成 53 单元)。
> 任何写 bank 真源 / 已有导入件的动作都必须走下面五步(内核已实现,直接调用,
> 不要自己再造一遍:from xls_common import write_atomic; write_atomic(path, rows)):

# S9 标准写入模板:读现有 → 改 → 写临时 → 回读校验 → 原子替换
def write_atomic(path, rows, header, ncol=20):
    tmp = path + ".tmp_write"
    wb, ws = xlwt.Workbook(encoding="utf-8"), None
    ws = wb.add_sheet("Sheet1")
    for c, h in enumerate(header):
        ws.write(0, c, h)
    for ri, row in enumerate(rows, start=1):
        for ci, v in enumerate(row):
            if v == "" or v is None:
                continue                      # 跳过空值,别写 None
            ws.write(ri, ci, v)
    wb.save(tmp)
    # ① 回读:行数 + 逐格比对,任一对不上立刻删临时文件、放弃写入
    sh = xlrd.open_workbook(tmp).sheet_by_index(0)
    back = [[sh.cell_value(r, c) for c in range(sh.ncols)] for r in range(1, sh.nrows)]
    if len(back) != len(rows) or any(
            str(a[c]) != str(b[c])
            for a, b in zip(back, rows) for c in range(ncol)):
        os.remove(tmp)
        raise SystemExit("回读校验失败,已放弃写入 " + path)
    # ② 原子替换:避免写一半被打断留下坏文件
    os.replace(tmp, path)                     # 成功 → 删掉 .bak 之外的旧文件
    return len(back)

配套三条硬要求:

  1. 写之前 shutil.copy2(path, path + ".bak_<日期>"),且备份要在改动前做。
  2. 幂等:脚本能重复跑(已存在则跳过;drop_clones 之类的剔除要「再跑一次剔除 0」),
    否则下次重跑会重复追加或重复剔除。
  3. 改完必须回读复核一次真实结果(单元数 / 小题数 / 关键列),不要相信内存里的 rows。

> 顺带:行序变了要同步重建伴生文件(答案 txt、溯源 md),见 A9。

S10 · 校验(第 5 章)


4. 输出规范

4.1 20 列结构与表头命名

标准表头(顺序不可变,与 importQuestionTemplateNew(题库导入模板).xls 一致):

目录 | 题目类型 | 自定义题型 | 大题题干 | 小题题型 | 小题题干 | 正确答案 | 答案解析
| 难易度 | 知识点 | 标签 | 选项数 | 选项A | 选项B | 选项C | 选项D
| 选项E | 选项F | 选项G | 选项H

> 模板无音频列、无图片列。

列 索引 字段 必填 填写规范
A 0 目录 ✅ 形如 /Unit 1 / /高中/单项选择;仅大题行填,小题行留空;不留旧前缀残留
B 1 题目类型 ✅ 仅认可:单选题、多选题、填空题(分录题/资料题)、判断题、简答题(名词解释/论述题)、连线题、排序题、完型填空、阅读理解、共用选项题、选做题
C 2 自定义题型 — 仅自定义新题型时填,常规题留空
D 3 大题题干 ✅ 独立题的题干写这里;组合题的材料写这里
E 4 小题题型 — 仅组合题小题行填,取值受平台支持列表限制(见 4.2)
F 5 小题题干 — 仅组合题小题行填
G 6 正确答案 ✅ 见 4.2
H 7 答案解析 — 选填;不可写参考答案/范文(会印到卷面)
I 8 难易度 — 仅 易/中/难,不填默认中等
J 9 知识点 — ⚠️ 仅当课程已存在同名知识点节点才挂载,未命中静默忽略(不像标签会自动新建)
K 10 标签 — 多个用 ; 隔开;未命中会自动新建一级标签
L 11 选项数 ✅ 必须与该行实际填写的选项列数一致,否则报「模板格式错误」;判断题 = 2
M–T 12–19 选项A–H — 只填正文,不带 A. / B. / A、 前缀;正文前补 1 个 NBSP(U+00A0)

4.2 单元格填写规则(高频,逐条对照)

题型 正确答案列 G 选项数 L 选项 A/B 列内容 题干空位
单选题 单个字母 A…D 选项实际个数 选项正文 + 前导 NBSP ______
多选题 升序无重复 ABC 选项实际个数 选项正文 + 前导 NBSP ______
判断题 A(正确)/ B(错误) 2 A=正确、B=错误(都加 NBSP) —
填空题(独立) 字母序列 ABCDE(5 空) 空数 A/B/C… = 各空答案本体,不加 NBSP ______
填空题(组合题小题) A(单空) 1 选项A = 该空答案本体,不加 NBSP 本小题那一句
简答题(翻译/写作) A 1 选项A = 参考译文/范文,不加 NBSP —
完型填空大题行 空 空 空 ##1##…##M##
完型填空小题行 该空正确项字母 4 四个选项正文 + NBSP 留空(靠 ##n## 定位)
阅读理解大题/小题 同上 同上 同上 小题题干在 F 列

通用填充细则

  1. NBSP(U+00A0):平台渲染选项时按「字母 + .」与正文直接拼接、不补空格,所以必须自己在正文前补 1 个 NBSP。
    - ❌ 普通半角空格:浏览器按 HTML 空白折叠规则吃掉前导空格
    - ❌ 全角空格 U+3000:Java String.strip() 视其为空白,导入解析时剥掉
    - ✅ NBSP:浏览器不折叠;Character.isWhitespace('\u00a0') 为 false
    - 例外:填空题、简答题的「选项 A–H」列存的是答案/范文本体,补前导空格会污染参考答案、导致判错 → 必须跳过。
  2. 多空答案字母序列:每位都要有对应选项列;某空多解时在该格用 ; 分隔。
  3. 组合题小题行留空属合法(继承大题),校验报告里单独说明,不算空缺项。
  4. 参考答案/范文只能进「选项A」,解析里放采分点、评分维度、句式得分点。

4.3 字符与编码

项 要求
文件编码 文件本身是 BIFF 二进制 .xls(与模板同格式),无 BOM 问题
单元格文本 统一 UTF-8 语义读入,写出前清控制字符(\x01 等)
换行 单元格内 \n + wrap=1
禁止 合并单元格、超链接、公式、HTML 实体、控制字符
空格 只在「选项正文前」用 NBSP;别处一律普通空格

4.4 文件与目录命名

对象 命名规范 示例
单档导入件 <档位>_学习通题库导入.xls 高中_学习通题库导入.xls
分包(题数 > 999) <档位>_学习通题库导入_分包N.xls 高中_学习通题库导入_分包1.xls
补导缺题型包 <档位>_学习通题库导入_补导缺题型N题.xls 本科大一_学习通题库导入_补导缺题型806题.xls
专项补导包 <档位>_学习通题库导入_<题型>补导<N>组.xls 高中_学习通题库导入_完形补导16组.xls
8 档合并件 分层题库_8档全合并_学习通题库导入_总表.xls + 分包1..N.xls —

> 平台内目录 = 「目录」列的值,建议一个档位只保留一棵目录树;重导前先删平台旧目录(私有 高中 + 公开 高中英语 之类),否则叠加。


5. 校验清单(交付前自检 + 报错修正)

5.1 必跑自检(逐条断言,任一不过不得交付)

# 检查项 判据
1 表头 vs 模板 20 列名与顺序完全一致;说明行已删
2 简单题布局 题目类型∈{单选题,简答题,填空题} 的行:D 列有真题干、F(小题题干)列必须为空、E 列为空
3 组合题大题行 除 A/B/D/I/J/K 外全空(含 C 自定义题型、E 小题题型必须空)
4 小题行 B=='' and E!='' 才算小题;A 列留空
5 选项列前缀 ^\s*[A-Ha-h]\s*[..、\))::] 零命中
6 题干前缀 ^\s*[\((]?\s*\d{1,3}\s*[\))\..、::]\s*(?![0-9]) 零命中(D 与 F 两列都查)
7 选项间距 选择题选项列必须 NBSP 开头;填空题/简答题的选项列必须不带 NBSP。<br>⚠️ **判定代码只能用 ASCII 空白 strip(v.lstrip(&quot; \t\r\n&quot;))——str.strip() 会把 NBSP 一起剥掉,把「已加 NBSP」误判成「没加」,全表假告警(2026-09-25 实测)
8 选项数与实填 每行 选项数 == 实际填写的选项列数
9 答案合法性 字母落在选项范围内;多选升序无重复;单选/多选选项内容两两不同
10 答案与题型匹配 单选 1 字母 / 多选升序多字母 / 判断 ∈{A,B} / 填空为字母序列 / 简答=A
11 ## 计数 完型:大题 ##n## 个数 == 本组小题行数;其余题型(单选/简答/填空/阅读…)题干含 ## = FAIL——##n## 只许完形用,其余题型写 ______。⚠️ 2026-09-25 前代码只做了完形组配对、没做这条断言(文档写着「已反向验证」而代码里没有),已补齐
12 非法字符 \x01 == 0、&#x27;&amp;#39;&#x27; == 0;选项内无 ___/#/&amp;。<br>⚠️ &#x27;【&#x27; == 0 只对题干(D/F 列)成立——解析列(G)的【评分维度】【评分档次】【词库】是合法标注,全表扫会产生 900+ 条噪音把真问题埋掉(2026-09-25 实测)
13 目录归一 全表只有一个根前缀;无 //;无 英语 类旧残留
14 题量上限 每个待导入文件平台口径题数(= 独立题数 + 组合题组数)≤ 999,不是数据行数。⚠️ 组合题是「1 大题 + N 小题行」,一行阅读含 10 小题也只算 1 题;实测铁证:高中分包2 数据行 3522 / 平台口径 638 题,导入成功报「638 条」。按行数判会误判成必须切分包
15 完形对应 组号连续、空位编号与小题一一对应、无截断组
16 主观题 简答类选项A 非空、不带 NBSP;解析里不含参考答案全文
17 去重 简单题行指纹唯一、组合题单元指纹唯一(单元原子级)
18 答案对照 已并入第 24 项(自动配对 + 逐格对齐)
19 差异审计 重生成后「改前备份 vs 改后」逐单元格比对,非预期差异 = 0,无单元格被误清空
20 题量口径 报告写两个口径:数据行数(本地)/ 独立+组数(学习通计费口径)
21 答案完整性 每道有答案的题都取到了答案;无法识别题型 → FAIL
22 答案越界 答案字母落在本题选项数范围内
23 组合题小题题干 阅读/共用选项/选做的小题行 F 列非空、大题行留空
24 答案逐题比对 把答案文档的答案单元序列与 XLS 的序列逐格对齐(difflib,不是按下标硬比)后比对;不一致必须归零。⚠️ 答案文档按「单题库」拆、导入件按「档/分包」切,同名对不上是常态:verify.py 会自动在目录内挑覆盖率最高的那份配对,覆盖率 ≥50% 才判,<50% 只提示「无法配对」

> 21~24 已并入 verify.py,与 1~20 一次跑完;val.py 不再单独使用(逻辑已迁入)。

5.2 常见报错与修正办法

症状 首查 修正办法
某题型一题都没导入,平台不报错 铁律 1 / 简单题布局 题干归位 D 列、清理 E/F 残留列,重建重导
导入进度条卡在「正在识别 90%」 题数 > 1000 / ## 混入非完型 先怀疑超限 → 切 ≤999 分包;仍卡 → 全表搜 ##,非完型一律改 ______
报「模板格式错误」 选项数 选项数 与该行实际填的选项列数对齐
报「答案或选项格式不正确」,且不指哪题 选项重复 下载错误数据反查 → 跑 audit_dupopt.py 定位;按官方材料订正重复项,不得自创;实在无据则删重复项并把选项数改为实际值,列「需教师确认」
报「小题题型为空或不支持」,整组拒收 小题题型取值 归一为『单选题』;大题题型也要写对(完形写成阅读理解同样整组拒收)
导入后显示成 A.A. xxx / 43) xxx 平台重复补标记 选项列去字母前缀、题干去题号前缀,重跑清洗
导入后显示成 A.xxx(无间距) NBSP 选项正文前补 1 个 NBSP(填空题/简答题的答案列不加)
目录被拆成两棵 目录列残留旧前缀 修源库 + 修生成器,归一后重建
组合题数量翻倍 / 重导后重复 平台不对组合题去重 重导前先删平台旧目录;导入前做单元原子级去重
简单题重导被「重复过滤 0 条」 正常 平台按内容去重,无需处理
平台题数比本地少 计数口径 学习通「共 N 题」= 独立题 + 组合题组数;先按此口径复算再查拒收
题目详情「知识点」为空 知识点挂载机制 课程里先建同名知识点节点,或改用标签列承载
听力题无音频 模板无音频列 导入后在题目编辑页手动挂接音频,报告里列清单
图片选项为空 python-docx 读不到 scan_images.py + extract_optimg.py 导出,XLS 里写「(图片A)」占位 + 报告列「需人工补图」

6. 异常兜底与必须确认项

6.1 处理策略(按优先级)

情况 处置
官方答案与原卷冲突 以官方答案为录入依据,在解析注明,报告「原卷疑点」单列,不改答案
选项重复且官方材料无法佐证第三项 删重复项、选项数改实际值,列「需教师确认」;绝不臆造选项
某篇没有可靠答案键 整篇剔除,不猜不补;另找「单卷」答案源可复用
官方答案单元数与题号不一致 以答案单元数为准重排录入
多源答案冲突(A vs D) ① 先比对选项原文是否一致(不一致 ⇒ 弃非真题那一方);② 一致则拿原文定位句判定,不数源;③ 无法调和 ⇒ 整篇判失败
正文取到但答案键被截断 该页不可作答案源;正文可留用,但需另配答案源
截取的网页正文不完整 直接剔除,绝不「凭记忆补全」重建
组合卷的音频/图片 XLS 里占位 + 报告列清单,人工挂接
无从判断的映射 停下来问用户,不自创题型

6.2 必须向用户确认的问题(不确认不得自行决定)

  1. 模板版本与列序(20 列是否一致)
  2. 未覆盖的题型映射(如连线题、排序题、自定义题型)
  3. 超 8 个选项(I–O)的选词填空/连线题如何落地
  4. 音频、图片的挂接方式
  5. 是否存在历史目录需先删除 / 是否需要先清空平台旧题库
  6. 「知识点」列是否已在课程里建好同名节点
  7. 答案与原卷冲突时的取舍
  8. 某篇无可靠答案键时是「整篇剔除」还是「保留题干待人工补答」
  9. 难度配比口径(如本科 3:5:2、大二 2:5:3 之类分档要求)

7. 最小示例:输入 → 输出字段映射

7.1 输入素材(节选)

(a) 单选题(原卷排版)

1. The earth _____ around the sun when I was eight.
   A. went     B. goes     C. will go     D. has gone
答案 B

(b) 完形填空题(原卷排版)

Complete the passage. Each blank has four choices.
It was a cold morning. She ______ early and lit the stove.
1. A) got up  B) get up  C) getting up  D) gets up    → 答案 A
2. A) lights   B) light    C) lit        D) luminous   → 答案 C

(c) 英译汉简答题

Part V Translation
1) As you have done the market survey, I&#x27;d like to discuss with you the possibility of selling our products in the US.
(无参考答案)

7.2 输出(XLS 前 20 列,索引 0–19)

行 0 目录 1 题目类型 2 自定义 3 大题题干 4 小题题型 5 小题题干 6 正确答案 7 答案解析 8 难易度 9 知识点 10 标签 11 选项数 12 选项A 13 选项B 14 选项C 15 选项D …19 选项H
表头 目录 题目类型 自定义题型 大题题干 小题题型 小题题干 正确答案 答案解析 难易度 知识点 标签 选项数 选项A 选项B 选项C 选项D 选项E…H
行1 /初中/单项选择 单选题 (空) &lt;NBSP&gt;The earth ______ around the sun when I was eight. (空) (空) B (空) 中 (空) (空) 4 &lt;NBSP&gt;went &lt;NBSP&gt;goes &lt;NBSP&gt;will go &lt;NBSP&gt;has gone 空
行2 (空) (空) (空) (空) 单选题 (空) (空) (空) (空) (空) (空) (空) (空) (空) (空) (空) 空
行3 /初中/完形填空 完型填空 (空) It was a cold morning. She &lt;NBSP&gt;##1##&lt;NBSP&gt; early and &lt;NBSP&gt;##2##&lt;NBSP&gt; the stove. (空) (空) (空) (空) (空) (空) (空) (空) (空) (空) (空) (空) 空
行4 (空) (空) (空) (空) 单选题 (空) A (空) (空) (空) (空) 4 &lt;NBSP&gt;got up &lt;NBSP&gt;get up &lt;NBSP&gt;getting up &lt;NBSP&gt;gets up 空
行5 (空) (空) (空) (空) 单选题 (空) C (空) (空) (空) (空) 4 &lt;NBSP&gt;lights &lt;NBSP&gt;light &lt;NBSP&gt;lit &lt;NBSP&gt;luminous 空
行6 /高职/翻译 简答题 (空) As you have done the market survey, I&#x27;d like to discuss with you the possibility of selling our products in the US. (空) (空) A 【PRETCO真题·官方参考译文】 中 (空) (空) 1 你已经作了市场调查,所以我想和你讨论在美国销售我们产品的可能性。 空 空 空 空

> 说明:
> - &lt;NBSP&gt; = U+00A0。行 1/3 的题干里也加了 NBSP(题干空白占位不影响渲染,但选项列必须有)。
> - 行 2 是干扰行,不应存在——独立题只占 1 行(此题若写成两行即触发「声明小题却无小题行」,会被静默丢弃)。
> - 行 3–5 是完型单元:大题行 ##1##/##2## 与两个小题行一一对应;小题行 A/B 两列留空,答案写在「正确答案」列、选项写在选项列。
> - 行 6 英译汉:正确答案=A、选项A=译文、选项数=1,译文放选项A 而非答案解析(放解析会印到卷面)。

7.3 校验对照

检查 结果
简单题布局(行 1、6) D 列有真题干、E 列空 ✅
组合题大题行(行 3) 除 A/B/D 外全空 ✅
选项前缀 零命中 ✅
题干题号前缀 零命中 ✅
NBSP 选项列有、简答选项A 无 ✅
## 计数 完型大题 2 个 == 小题行 2 ✅;其余为 0 ✅
选项数 行 1 = 4(实填 A–D)✅;行 6 = 1 ✅
题量 本地 4 题;学习通口径 3 题(独立 2 + 完型 1 组)✅

附录 A:规则库索引(历史坑集,已去重编号)

> 以下条目为历次实测沉淀,与正文规则一致但更具体,遇到对应症状时查这里。

A1 · 平台会补什么,你就不写什么(同源于坑 1/2/3)
选项列补字母 → 不写字母;题干补题号 → 不写题号;空格不补 → 自己补 NBSP。最省事的自检是把模板示例行当基准逐字比对。

A2 · 题库题量口径(2026-09-12 B3 全库实测,10/10 零误差)
共 N 题 = 独立题数 + 组合题组数,组合题整组算 1 题。用户报「题数变少」时的诊断顺序:① 先用该口径复算;② 再查是否组合题被拒收;③ 最后去原卷确认分节数差异。不要凭「同一套卷应该一样」回改数据。

A3 · 大编号题源(空位全局连续编号)三条铁律(2026-09-13)
① 篇章切分靠「编号按每篇空数成组」的全局不变量,不靠分隔句;
② 锚定用「逐号顺搜」(?&lt;![\d.\.])N(?![\d]) 跳过正文数字;OCR 把编号变裸下划线时按「裸下划线(≥3) + 紧跟 (word) + gap>1」回补;
③ 渲染只能「按已知坐标替换」,绝不用正则扫全文数字(会把 2025、16th-century、1960s 吞成空位)。
附:Passage N 标题行必须整行剥除;sentence_bounds 需先跨过空位标记再找句末标点;OCR 重复块按「不同编号集合覆盖率 ≥ 70%」裁掉。

A4 · 语法填空编号区间按卷型不同(2026-09-13)
| 卷型 | 编号 | lo/hi/off |
|---|---|---|
| 新高考 I/II、浙江卷 | 56–65 | 56/65/55 |
| 全国甲/乙卷、2014–2020 全国卷 | 61–70 | 61/70/60 |
| 北京卷 2021+ | 11–20 | 11/20/10 |
| 北京卷 2019/2020 | 1–10 | 1/10/0 |
⚠️ 区间逐卷核对原卷,不能按卷种想当然。北京卷 2021 起由 1–10 改为 11–20。

A5 · 公网抓取通道分级(2026-09-13)
| 通道 | 可用性 |
|---|---|
| zy.21cnjy.com/&lt;id&gt; | ✅ 首选(原文+选项+答案+解析一次拿全) |
| mip.21cnjy.com/P/&lt;id&gt;.html、m.51jiaoxi.com/doc-*.html | ✅ |
| bigxun.com、zxxk.com | ✅ 作第二源 |
| renrendoc.com、wenku.baidu.com | ⚠️ 抓不到正文,但搜索片段常带完整答案键 |
| gzyy.cooco.net.cn | ❌ |
大批量补源时拆给多个检索子代理并行(每篇 ≥2 独立源、失败如实报、严禁编造)。

A6 · 答案冲突裁决(2026-09-13 Zafirakou 篇)
汇编类/精校类文档最爱把相邻段落信息安错人安错题。冲突时:① 比对选项原文(不一致 ⇒ 弃非真题那一方);② 一致则拿原文定位句判定;③ 仍无法调和 ⇒ 整篇剔除。

A7 · 双栏 PDF 抽取的交叉核验陷阱(2026-09-15)
用盘上解析 txt 做自动比对前先 re.sub(r&quot;【\s*\d+\s*】&quot;, &quot; &quot;, disk);命中率低时按区域 dump 人工逐句核,严禁据自动指标判错。汉译英的盘上答案只有英文译文,不能用中文原文特征串做覆盖检测。

A8 · 规模化抓题必须配独立答案审计代理(2026-09-15 CET-4 Sprint3)
随机抽检发现 1 处真错 ⇒ 全量复核。每个审计代理「先自行求解、不看已记录答案」,再与 ≥2 独立源比对,只输出 {source, stem_head, recorded, verdict, confidence, evidence};low 一律 DROP 而非改字母。定位键统一用「题干 strip() 后前 40 字符」——先截断再 strip 会因换行造成静默失配。反例警示:假订正与漏订正同样有害。

A9 · 伴生文件必须按「XLS 输出行序」生成(2026-09-15)
症状:Gate1 报「答案序列不一致」,肉眼逐题却全对。根因:XLS 按目录/维度分组写出,答案 txt 按取数顺序写 → 整体错位。生成答案文档时直接遍历最终写出的行。

A10 · 难度配比
主观题无难度公式,用分位法(25%/75%)按题量切易/中/难;⚠️ 分数离散时改用「秩次法」(按 (score, 序号) 排序后取秩位切点),否则分位法会落在一堆同分值中间(实测从 23/40/37 修到精确 0.25/0.5/0.25)。

A11 · 自建校验器的坑(两条都实测过)

① 用 _{2,}(?!\s*[((]) 判「该空无提示词」会失效——负向前瞻失败后 _{2,} 回溯到更短匹配使 (?!) 成立,产出大量假告警。正解:两遍法,先收集「带括注」的空号集合,其余即无提示词。

② 判 NBSP 前只能用 ASCII 空白 strip:str.strip() / lstrip() 默认会把 \xa0 当空白剥掉,于是「已正确加 NBSP」被判成「缺 NBSP」,全表假告警(2026-09-25 verify.py 首测即中招)。正解:v.lstrip(&quot; \t\r\n&quot;),空判定用 v.strip(&quot; \t\r\n&quot;)。

③ 「跳过后续小题行」必须另用游标 j 从 i+1 起,不能拿已有的 i 做自增循环变量——写成

while i &lt; len(rows) and not rows[i][1].strip(): i += 1   # ← 错:题型非空时立即为 False,i 不前进

会让外层 while i &lt; len(rows) 空转死循环(2026-09-25 实测 verify.py 卡死 3 分钟、faulthandler 才定位到行号)。正确写法是

j = i + 1
while j &lt; len(rows) and not rows[j][1].strip(): j += 1
i = j

A12 · 「已有标签」会误导你以为某卷空白(2026-09-15)
已入库条目可能标注为「全国」「海南」却实为「2020 新高考I 卷 C/B 篇」。抓取整卷前先拉现有 id 清单逐条核对卷别,合并时把疑似重复全打 skip 人工过目,绝不直接覆盖。

A13 · write_xls() 的表头会被写两遍(2026-09-25)
入参既可能是「已含表头」(build() 的返回形态),也可能是「纯数据行」。三处必踩:
① 无条件写表头 + 数据从 enumerate(rows, start=1) → 表头重复、整表行号 +1;
② 只改 start 不改 body → 多出一行空白、表头被推到第 2 行;
③ 判断出「已含表头」却只写数据不写表头 → 表头行全空。
正解:has_hdr = rows[0] == HEADER,body = rows[1:] if has_hdr else rows,
表头行单独写一行(取值优先用原表头),数据 enumerate(body, start=1)。
症状:某文件突然多 1 行、行号整体错位、题量虚高 1,进而误判「1000 > 999 超限」。

A14 · 答案文档与导入件的「同名配对」几乎永远失败(2026-09-25)
答案文档按单题库拆(初中_单项选择_ans.txt 之类),导入件按档/分包切,
名字天然对不上 —— 16 件交付件当初全部报「未配对、跳过比对」,等于第 24 项在真实
交付上从没跑过。且按下标硬比必然报「首个差异 #1」:单库答案在整卷里只是中间一块。
正解:用 difflib.SequenceMatcher 把「题库序列」当 a、「文档序列」当 b 求 opcodes,
只在 replace/insert/delete 里逐格比并带上该单元对应的物理行号,
覆盖率 ≥50% 才判配对成功,≥0.9 的差异才判 FAIL(配对可信),低覆盖只 WARN。

A15 · 「整表覆写」事故:xlwt.Workbook() 新建 + save() 不是追加(2026-09-25)
症状:不报错,但被写的库从 100 单元/500 小题变成 53 单元/318 行,题量凭空少一半,
且「少了的那一批」查无遗迹(内存里的 rows 看着是对的,只有落盘结果不对)。
根因:xlwt.Workbook() 起的是一张空表,save() 直接覆盖目标文件,少了「读旧 + 合并」一步。
正解:五步原子写(读现有 → 改 → 写临时 → 回读校验 → os.replace,模板见 S9),
外加三条配套:.bak_&lt;日期&gt; 备份、脚本幂等、落盘后立刻 xlrd 回读断言单元数/小题数/关键列。

> 同类错误的另一面:只删导入件不动 bank 真源 → 下次重跑生成器原样带回;
> 只删 bank 真源不重跑生成器 → 导入件与真源不一致。二者必须同批落地,
> 并以「真源再跑 drop_clones 剔除 0」验证幂等(高职阅读 / 大三语法填空两轮均照此执行)。

A16 · 删克隆要按「小题集合指纹」,不是「全单元指纹」(2026-09-25)
克隆对只在篇章/解析/篇号上有差异 → 用「小题题干+答案+选项」排序后的集合指纹判重
(_sub_fp),而不是整单元拼接指纹。顺序铁律:先 drop_clones(),再 dedup_units(),
反了会被行级去重截成半截组合题。判完必须人工抽验 8–10 篇,确认每篇小题数与空位数一致。

A17 · 清理类操作的「假绿」陷阱:命中数 vs 归档条目数必须双印证(2026-09-25)
批量删 .log / .bak 类脏数据时,若「扫描清单」与「执行脚本」相隔数分钟(跨工具调用很常见),
目标可能已被外部删除(手工清理 / 同步盘 / 其它进程),脚本会静默命中 0 并在报告里写成已清理。
两条硬要求:① 归档 zip 的条目数与命中数必须一致——zipfile.ZipFile(z).namelist() 自查;
② 执行前再 os.path.exists() 复测一次总数。任一项不符即如实上报「该批未被本轮删除」,
不得含糊写成「已清理」。另:匹配备份别只写 .bak_20260925,…_xls.bak_item17_20260925
这类前后缀变体要单独列,否则会漏。
再次命中(09-25 夜间):dry-run 报「可删 56 个」,执行时归档只收进 38 条,差 18 个。
这一批同样是被外部删的。凡 dry-run 数与归档条目数不等,一律按「有文件在本轮之外消失」上报,
不要解释成"预估误差"。

A18 · 删备份前先 grep「谁在读取它」(2026-09-25)
.bak 不一定只读不写——有些脚本把它当输入基表。09-25 实测:bank_quota.json.bak_20260920_大二入账
被 _work/_quota_fix_daer.py 读取、…_p3b 被 patch_ledger_p3b.py 读取、…_p6_junior 被
patch_ledger_p6.py/p6b.py 读取。删了不会报错,只会让这些脚本下次崩在文件打开上。
删除任何 .bak 前必做:grep -rn &quot;\.bak&quot; --include=&quot;*.py&quot; 全库扫一遍,命中的一律进保留清单。

A19 · 备份的四种定性(决定删/留,别只看后缀)(2026-09-25)

类别 判据 处置
A1 冗余 与同族正式件 md5 相同 删
A2 中间态 同族正式件存在、内容不同("改动前快照") 删(先归档)
B 唯一副本 同目录 + 3 层父目录均找不到同族正式件 留
C 脚本依赖 grep 到被 .py 读取 留

判定脚本自身两个反直觉陷阱(都真实踩过,会直接误判):
① os.path.splitext(&#x27;x.json.bak_20260920&#x27;) 拿不到基名 → 所有条目被当成"无同族正式件"(误判 B);
改用 split 法:name.split(&#x27;.bak&#x27;)[0] 之类逐令牌剥离。
② 修好基名后又出现自匹配——怪名文件把自己的变形当成同族正式件,判成 A1 冗余被误删;
必须显式排除自身路径:if os.path.abspath(sib) == os.path.abspath(p): sib = None。
③ 易误判为 B 的一类:_work/backup_20260924/*.xls("前目录归一"快照,正式件已迁移到别处)——
这类是真唯一副本,必须留。


参考脚本(本 skill 的 scripts/ 目录)

按「先取素材 → 再构建 → 后校验 → 出报告」的顺序使用。

脚本 作用
lib.py 推荐主库:Bank 类(mc / fill / shared / shared_sub / cloze / reading / judge / R / save)。R() 自动对 D/F 跑 clean_stem()、对选项列跑 clean_opt() + pad_opt()
build_template.py build 骨架(clean_opt() + R() 行构造器 + xlwt 写出)
validate_template.py 模板感知校验器
val.py 答案逐题比对器(同行多题、T/F→A/B、简答跳过)。已并入 verify.py 第 24 项,单独跑仅为回溯旧报告用
norm_ans.py 答案文档规范化模板,产出 {KEY}_ans2.txt(见第 2.3 节)
detail.py 保序导出「段落 + 图片名 + 表格单元格(空位标 [___])」;图片同时解 DrawingML 与 VML
check.py 单份校验入口:python check.py &quot;&lt;名称&gt;&quot; &lt;xls&gt; &lt;答案txt&gt;
xls_common.py 规则内核:clean_stem / clean_opt / pad_opt / strip_ctrl / normalize_dir / fix_simple_layout / fill_cloze_substems / fix_cloze_markers / strip_source_tags / fix_subjective_answer / pad_substem_opts / row_sig / dedup_units / assert_clean / build() / write_xls()。第 3 章 S6 的代码就在这儿,直接 import
verify.py 第 5.1 节 1~23 项自检 + 第 24 项答案逐题比对的脚本化实现,一条命令跑完全流程:python verify.py a.xls b.xls / --dir &lt;目录&gt; / --all &lt;根目录&gt;(自动收目录内所有 *_ans.txt 做配对)。退出码 0/1。已用 4 个坏样本反向验证:简单题布局错位、选项带字母前缀、题干带题号、非完型含 ## 全部能抓到
demo_minimal.py 第 7 章最小示例的生成器,跑一次即得可对照的 5 行 XLS
verify_opt.py 列自检(选项零字母前缀 / 题干零题号前缀 / NBSP 间距 / 选项数一致 / 答案范围 / 题型标准值)
audit_dupopt.py 全量体检已产出 .xls:选项重复 / 选项数不符 / 答案越界 / 字母前缀 / 题干前缀(导入被拒时先跑它定位是哪一题)
run_all.py + spec_all.py 批量复跑全部登记文件(改动 val.py/lib.py 后必跑,防回归)
selftest_neg.py 反向自测:造 5 类坏样本(选项字母前缀 / 简单题布局反写 / 题干带题号 / 非完型残留 ## / 答案越界)逐条验证 verify.py 能抓到。改了 verify.py 必跑,退出码非 0 = 有漏检;临时文件自动清理
strip_prefix.py 已生成 xls 的就地修复(扣选项列误写的字母前缀)
scan_stemnum.py 列出题干仍带题号前缀的行(D/F 两列 + 行号 + 原文)
diff_prestem.py / diff_prepad.py / diff_dupopt.py 「改前备份 vs 改后」逐单元格差异审计(确认改动只落在预期列)
scan_images.py 扫描 docx 内图片/文本框数量,判断有无「图片选项」
dump_textbox.py 提取 docx 文本框(txbxContent) 内的文字——python-docx 读不到,选项库常藏这里
extract_optimg.py 按文档顺序导出图片选项,命名 &lt;卷&gt;_Q&lt;题号&gt;_&lt;选项&gt;.png

收工前 checklist(照抄执行)

  1. 自检清单 1~24 项全部通过,输出报告。
  2. 逐份清点题量(本地口径 + 学习通口径并列),与官方答案键比对「0 错 0 警」。
  3. 报告固定包含三块:① 逐份清单;② 需人工补全(音频 / 图片挂接);③ 原卷疑点与异常题目。
  4. 明确告知用户:图片/音频需在学习通题目编辑页手动挂接;知识点列需课程里先建同名节点。
  5. 提醒用户:重导前先删平台旧目录;组合题文件不可重复导入(平台不去重)。
  6. 凡写过 XLS 的,落盘后回读复核一次(行数 / 单元数 / 关键列),并把备份路径写进报告;
    改过行序的,同步重建答案 txt 等伴生文件。

常见问题

5 问
答案由本站依据条目字段整理
学习通题库导入 · XLS 生成怎么安装?

在支持 Skills 的客户端里执行:skillhub install user_3853b7f7/xuetang-question-bank-import。安装方式为未标注。装完刷新技能列表或重开客户端。

学习通题库导入 · XLS 生成支持哪些客户端?

资料没有标注宿主客户端,但只要客户端支持 Skills(Claude、Codex、Cursor 等),一般都能加载。

学习通题库导入 · XLS 生成权限高吗,安全吗?

权限级别为未标注权限。安装前先看它会读取或写入哪些内容。

学习通题库导入 · XLS 生成收费吗?

本站不代收费用,也没有标注具体价格。是否收费取决于技能本身和所用的模型或客户端,正式使用前按作者说明确认。

学习通题库导入 · XLS 生成用什么许可证?

许可证标注为 未说明(许可证不明确)。商用或二次分发前请到仓库确认条款原文。

热门专题

按场景挑技能
全部专题 →

技能内容以作者仓库为准;分类、权限级别与许可证状态的中文说明为中文整理,最近核验 未标注。