简介在日常办公与备考场景中我们经常会收到来自网络的.doc文档这类旧版Word格式可能携带宏病毒因此安全打开是第一步。理解Office受保护视图的原理合理设置信任中心并用PowerShell或oletools进行预检能有效规避风险。将.doc转换为.docx则是后续利用python-docx等工具提取文本的基础LibreOffice头模式提供了高效批量转换方案。针对覆盖计算机二级C语言、计算机组成原理等考点的训练题文档借助正则表达式可将题目结构化进而构建自测题库。文章以一份实际训练题文件为例演示从安全验证、格式转换到题库拆解的完整流程帮助备考者高效刷题、查漏补缺。1. “计算机训练题.doc”到底是什么一份能直接刷的题库还是一个要拆的怪盒如果你在考研群、毕设小组或同事U盘里拿到一份名为“[详细完整版]计算机训练题.doc”的文件第一反应多半是双击打开。可Windows常常会弹出“你尝试预览的文件可能对你的计算机有害。如果你信任此文件以及其来源请打开此文”很多人被这句警告劝退顺手就把文件删了。这份文档的真实身份大概率是一份覆盖计算机基础、计算机组成原理、计算机二级C语言常考点的训练题集只是它被塞进了老旧的.doc容器里正文里还带着公式、图片甚至早期文档才有的宏。这篇文章不聊虚的就讲我拿到这类文件后怎么安全打开、怎么把题目结构化、哪些坑会让人白折腾一晚上。适合备考计算机二级、复习计算机组成原理和计算机系统结构的读者照着走一遍。2. 打开.doc前的安全课为什么Windows会警告“对计算机有害”以及怎么正确解除2.1 先搞懂警告来源宏、外部链接和“保护视图”当Windows弹出一句“你尝试预览的文件可能对你的计算机有害”时很多人第一反应是杀毒软件报毒了其实这是Office的受保护视图提醒。受保护视图的逻辑是对来自Internet、邮件附件或受限目录的文档先在一个隔离环境里渲染预览默认禁止编辑、禁止宏、禁止ActiveX控件。这么做的目的就是为了防止一份看似正常的doc在你双击的瞬间执行恶意代码。所以“预览可能有害”这句话的准确含义是在没确认内容之前最稳妥的办法是只看不编辑。为什么这类警告总跟.doc绑在一起因为.doc是OLE2复合文档格式它可以嵌入宏、嵌入对象、嵌入DDE域和外部链接。历史上以宏病毒形式传播的恶意Word文档绝大多数都采用.doc后缀。Kill宏病毒的原理是检测VBA工程里是否有AutoOpen、DocumentOpen这类自动宏。如果某个训练题doc里有自动宏你双击打开的一瞬间宏代码就可能运行。所以看到一个旧版训练题doc第一件事不是看题而是看它有没有宏。还要注意一个细节文件资源管理器在显示“来自Internet”时实际上给文件关联了一条NTFS数据流Zone.Identifier。Office读到ZoneId为3Internet时就启用受保护视图。你可以把文件从下载目录拖到桌面这条标记仍然存在因为标记跟随文件本身而不是目录。所以“我从下载文件夹拷出来了它应该安全”这种想法靠不住。在Windows里我一般这样判断文件大小小于10KB但文件名写着“详细完整版”可疑文件属性里没有作者、没有修订信息只有“来自Internet”可疑双击后打开进入受保护视图说明确有标记不是杀毒误报杀毒软件扫描无异常只能说明没有已知病毒不能说明没有宏。真正拿到训练题doc别急着双击。先做扫描再看宏再决定要不要“启用编辑”。这套习惯能挡掉绝大多数麻烦。2.2 用Word/WPS的安全打开三连解除锁定、信任中心与只读启动在确认文件来源基本可信后再用办公软件打开。这里的操作顺序我总结成“先解除锁定再设宏安全最后只读启动”。解除锁定在文件上右键“属性”常规页签底部有一个“解除锁定”复选框前面有个安全锁图标。勾上它Windows会删除文件上的Zone.Identifier标记。这样再双击Office就不会强行用受保护视图打开这个文件。注意只有文件确实来自Internet时这个复选框才会出现。如果文件是通过FTP、本地U盘拷贝过来的可能没有这个选项那就跳过不影响后面。宏设置打开Word后进入“文件 选项 信任中心 信任中心设置 宏设置”选择“禁用所有宏并发出通知”。这个选项的意思是文档里的宏不会自动执行但如果文档确实包含宏Word会弹一个通知条提醒我。相比之下“禁用所有宏而不通知”过于安静反而让我不知道这文件里带没带宏“启用所有宏”则完全是给恶意文档开门不要选。WPS里对应位置通常在“设置 安全设置 宏安全性”同样选禁用。只读启动在Word里用“文件 打开”选中文件后不直接双击而是点击打开按钮旁边的下拉箭头选“以只读方式打开”。如果担心宏写入文件这个操作能保证当前会话只读。训练题嘛本来就只需要看不需要改原文件。只读打开后如果看到“启用编辑”按钮点它不会让宏自动运行只要你不点“启用内容”。宏设置是“禁用并通知”所以此时“启用内容”才是放行的开关。还有一点值得说如果只是临时看题不需要把训练题doc转成docx直接看就行。一旦想修改或者做题库就另存为docx。另存的过程会把旧的OLE对象重新封装一遍文档里的VBA宏如果是不受欢迎的Word通常会在保存时提示或清除相关宏。这等于给文件做了一次“净化”。2.3 不靠Office也能验货用PowerShell和oletools取样很多情况下我不想打开Word再判断尤其是来路不明的“[详细完整版]计算机训练题.doc”。命令行比图形界面更适合批量排查我先看文件有没有Internet标记再算哈希然后扫宏。# 查看文件是否带着来自网络的Zone.Identifier标记 Get-Item -Path C:\Users\test\Downloads\[详细完整版]计算机训练题.doc -Stream Zone.Identifier -ErrorAction SilentlyContinue | Format-List # 计算SHA256留底之后方便跟发布者核对文件是否一致 Get-FileHash -Path C:\Users\test\Downloads\[详细完整版]计算机训练题.doc -Algorithm SHA256 | Format-List第一条命令如果输出ZoneId3说明文件确实来自Internet如果没有任何输出可能是本机生成的也可能是所在磁盘不支持NTFS流。第二条命令生成一个64位哈希值这个值相当于文件指纹。拿到指纹后发给传文件给你的人他在自己电脑上算一遍SHA256如果两个哈希一致说明文件在传输过程中没有被替换也没有发生损坏。这个操作在排查“文档打开报错”时特别好用因为很多“.doc打不开”其实根本不是Office问题是文件从网盘下载下来少了一半字节。看完哈希再扫宏。先安装oletoolspip install oletools olevba -c C:\Users\test\Downloads\[详细完整版]计算机训练题.doc-c参数让olevba只打印检测到的宏代码。如果输出区域显示“VBA Macros: No”说明这个doc里没有VBA工程可以放心用Word打开。如果显示有AutoOpen、DocumentOpen这类自动宏就要警惕最好先搞明白宏里面的代码到底干什么。注意oletools还能检测DDE、外部关系但命令行里最常用的是olevba和oleid。一个训练题doc如果同时满足“来自Internet 没有宏 哈希正常”基本可以确定只是普通文档。提示把doc拖进在线扫描服务前先想清楚里面有没有个人或敏感信息。训练题通常不涉及隐私但如果你不放心还是本地用oletools扫更稳妥。3. 把.doc里的训练题变成可用的题库文本提取与结构化3.1 为什么不能直接用python-docx打开.doc先转成.docx刷题刷多了就会发现手工翻Word文档效率太低尤其这份“训练题doc”可能有几百道题。很多人想写脚本提取文本第一步就翻了车python-docx打开.doc文件直接抛PackageNotFoundError或docx file invalid。原因不是代码写错而是python-docx只支持Office Open XML格式也就是.docx。doc是OLE2复合文档内部结构是一堆Stream和Storage跟docx的ZIP目录结构完全是两码事。Windows上最简单的方案是手动用Word打开然后另存为docx但只能一个文件一个文件地转。如果训练题有好几个doc手工操作非常浪费时间。我一般用LibreOffice的无头模式批量转换。LibreOffice是免费开源办公套件有命令行接口能跑在Windows、Linux和macOS上。mkdir -p converted libreoffice --headless --convert-to docx [详细完整版]计算机训练题.doc --outdir converted--headless表示不启动图形界面适合在服务器上跑--convert-to docx指定输出格式--outdir converted把生成的docx放到converted目录。如果遇到包含中文文件名的情况建议保持双引号包裹否则部分Linux shell会因括号或空格解析错乱。Windows下如果提示libreoffice: command not found是因为安装时没有把LibreOffice写进PATH。可以用全路径执行 C:\Program Files\LibreOffice\program\soffice.exe --headless --convert-to docx C:\work\[详细完整版]计算机训练题.doc --outdir C:\work\converted需要批量转换时在Linux/macOS下用循环for f in *.doc; do libreoffice --headless --convert-to docx $f --outdir converted; done在Windows PowerShell下这样写Get-ChildItem *.doc | ForEach-Object { C:\Program Files\LibreOffice\program\soffice.exe --headless --convert-to docx $_.FullName --outdir converted }这里$_.FullName是当前文件的完整路径避免工作目录不同导致找不到源文件。转换时间不长几兆的文件耗时几秒钟。转换过程如果报错通常有三种LibreOffice没有安装、源文件被占用、输出目录不存在。先创建converted目录再执行命令。3.2 遇到“dify unstructured api url is not configured for doc file processing”时怎么绕开除了本地刷题还有人想把这套训练题喂给AI知识库让大模型根据这份doc出题或者答疑。常见做法是使用Dify这类平台搭建一个知识库上传文档后让平台自动抽取文本。如果你直接把“.doc”拖上去平台往往回你一句dify unstructured api url is not configured for doc file processing。这句话的意思是Dify处理doc文件依赖一个叫Unstructured的文档解析服务而部署Dify时后台没有配置那个服务的API地址。于是系统无法对doc做文本抽取。这个报错跟你的训练题没关系是平台配置缺失。两条出路第一条如果你能控制Dify服务的环境变量到后台配置UNSTRUCTURED_API_URL让它指向可用的Unstructured服务地址。第二条也是最省事的一条不要直接传doc而是先按3.1节的方法在本地把doc转成docx再上传。Dify对docx的解析不需要调Unstructured因为它自身能读取docx内部的文本节点。我在部署经验里吃过这个亏后来凡是遇到doc文件都养成了先转docx再喂平台的习惯。这不仅能绕开Dify的配置问题也能减少其他知识库工具的兼容性报错。如果坚持要在本地起Unstructured服务可以用Docker起一个镜像把宿主机端口映射成服务端口然后在Dify的配置里填http://localhost:8000。但这对于一份训练题来说明显是杀鸡用牛刀。本地转格式是零依赖的兜底方案。3.3 用正则把题目拆成结构化条目题号、题干、选项、答案转成docx后真正的难点是把杂乱的题目拆成结构化数据。我先把拆题过程拆成两步第一步统计题号格式第二步按统计结果做正式拆分。先写统计脚本from collections import Counter from docx import Document doc Document(converted/[详细完整版]计算机训练题.docx) patterns Counter() for para in doc.paragraphs: text para.text.strip() if not text: continue m re.match(r^(\d{1,3})[\.、\)], text) if m: patterns[m.group(1) .] 1 elif re.match(r^第[\d一二三四五六七八九十百]题, text): patterns[第X题] 1 elif re.match(r^[A-D][\.、\)], text): patterns[选项] 1 print(patterns.most_common(10))这段代码遍历每个段落分别统计“1.”“第1题”和“A.”三类开头的数量。输出能告诉你这份训练题的主要排版风格。如果“第X题”出现次数很多正式拆分时就要优先用中文题号。如果“1.”很多就用数字题号。不要跳过这步因为Word训练题里经常出现“第2题”和“2、”混用直接写死正则会拆出大量垃圾条目。统计完以后执行正式拆分import re from docx import Document ITEMS [] CUR None def flush(): if CUR is not None: ITEMS.append(CUR) doc Document(converted/[详细完整版]计算机训练题.docx) for para in doc.paragraphs: text para.text.strip() if not text: continue # 数字题号1、 1. 1 1 m re.match(r^(\d{1,3})[\.、\)]\s*(.*), text) if m: flush() CUR { id: int(m.group(1)), question: m.group(2), options: [], body: [], answer: None } continue # 中文题号第1题 第2题 m re.match(r^第(\d)题\s*(.*), text) if m: flush() CUR { id: int(m.group(1)), question: m.group(2), options: [], body: [], answer: None } continue if CUR is None: continue # 选项行 m re.match(r^([A-D])[\.、\)]\s*(.*), text) if m: CUR[options].append((m.group(1), m.group(2))) continue # 答案行 m re.match(r^(答案|参考答案)[:]\s*([A-D]{1,4}), text) if m: CUR[answer] m.group(2) continue # 其他都算题干补充 CUR[body].append(text) flush() print(拆出题目数:, len(ITEMS))这段代码的关键是CUR字典它保存正在组装的一道题。遇到新的题号时先把上一题存进ITEMS再新建当前题。选项行单独匹配答案行同样单独匹配。正则里的(\d{1,3})限制题号最多三位目的是防止把“1.2 小节编号”误判成题目编号。如果训练题是多选题答案可能是“ABC”或“ABCD”正则里的[A-D]{1,4}就是这个作用。单选的答案字符串只有1个字符拆出来也不影响。有些训练题答案不跟题而是集中在文档末尾的“参考答案1-5 ABCDA6-10 BCDAB”这种段落。如果要处理这种集中式答案需要额外写一段区间解析。我的做法是单独读取以“参考答案”开头的段落用(\d)-(\d)\s*[:]?\s*([A-D])匹配题号区间和答案串然后把答案串按字符切开回填到对应题目的answer字段。这是拆题时最容易被忽略的部分因为如果答案行和题目不在一起上面这段代码拆出的所有答案都是None。另外python-docx的doc.paragraphs只包含段落不包含表格里的内容。如果训练题的题干或选项放在Word表格里段落遍历会漏掉。遇到这种情况我一般先用doc.tables把所有单元格文本抽出来再跟段落文本合并成一个“全文行列表”。合并后再跑拆分题目数量就对得上了。all_lines [] for p in doc.paragraphs: all_lines.append(p.text) for table in doc.tables: for row in table.rows: for cell in row.cells: all_lines.append(cell.text)注意表格里的文本顺序不一定是题目顺序因为Word表格有合并单元格和行列结构。如果源文档把一题一个表格顺序是对的如果所有题目塞进一个大表格取出来顺序容易乱。所以我在拆题前总会在统计脚本里加一行判断len(doc.tables)如果表格数量接近题目数说明是“题表格”结构可以用表格方式拆如果只有一个表格那还是先复制到文本编辑器里转成纯文本再处理比较保险。4. 围绕计算机组成原理与计算机二级C语言这份训练题怎么学才不白刷4.1 先把题目按“计算机系统结构/组成原理/操作系统/网络”归类训练题这种doc一般不会像教材那样按章节泾渭分明地排。它前面可能是Windows常识后面突然跳到进程调度再过两页又是C语言指针。从头刷到尾最大的问题是你刷完100道题根本不知道自己哪块弱。所以我拆完题以后第一件事是打标签。我给自己定的标签范围是四类组成原理包含计算机系统结构、操作系统、网络、C语言。这四类基本覆盖了计算机二级C语言和考研408的常考方向。打标签可以用关键词规则先初筛再人工确认。下面是一个可用的Python示例import re TAG_RULES [ (r(补码|原码|反码|浮点|IEEE|Cache|主存|流水线|中断|DMA|寻址|字长|ALU), 组成原理), (r(进程|线程|死锁|信号量|页面置换|虚拟内存|文件系统|磁盘调度), 操作系统), (r(TCP|UDP|IP地址|子网|交换机|路由器|OSI|帧|端口), 网络), (r(指针|数组|结构体|函数|递归|printf|scanf|sizeof), C语言), ] def classify(text): for pattern, label in TAG_RULES: if re.search(pattern, text): return label return 计算机基础分类规则很简单但很实用。看到“Cache”“主存”“流水线”几乎可以确定是组成原理题。看到“组间串行进位”这是并行进位链的考点属于计算机系统结构里比较经典的内容。这类题不能只看答案最好画一画进位链的传递逻辑否则遇到换一种参数的题又会错。有的训练题还会包含“计算机系统结构”和“计算机组成原理”的边界题比如区分“透明性”“并行性”。我的处理原则是只要题目在说硬件内部如何工作就归到组成原理只要题目在说整机属性或性能指标就归到计算机系统结构。不用搞得很严格刷题只是为了查漏补缺。标签打完后我给每类题用不同策略复习。C语言题先用编译器验证组成原理题动笔算网络和操作系统题重复记忆。如果一份训练题里“操作系统”类题目明显多说明这份doc的出题偏向系统方向如果“组成原理”类多那更像是考研复习材料。根据自己的目标调整刷题顺序比死磕原文档顺序效率高。4.2 二级C语言题的“三遍刷法”读题→画内存→对答案计算机二级C语言是这份训练题被广泛搜索的核心关键词。二级C语言考试里指针、数组、结构体、函数调用这些小题很多人看书感觉自己都会一到考试就发现输出跟预想的不一样。原因很简单C语言的内存模型不是靠眼睛看会的。我处理二级C语言题的固定方法是“三遍刷法”。第一遍只看题不碰编译器。遇到指针或数组的代码片段在草稿纸上画内存。四个字节的格子变量名写在上面指针用箭头指向格子。写出代码执行到每个语句后的状态。第二遍打开编译器把题干里的代码原样敲进去运行看实际输出跟手推的差在哪。绝大多数情况下差别来自的优先级、*p和(*p)的区别、数组下标从0开始的次数错误。第三遍把错的题号和关键字写进错题本。这个错题本不用写整题只写“*p等价于*(p)”这种一两行结论。下面这个C语言片段几乎能覆盖所有指针自加考点#include stdio.h int main(void) { int a[4] {1, 2, 3, 4}; int *p a; printf(p %p, *p %d\n, (void *)p, *p); printf(*p %d\n, *p); printf(after *p, *p %d\n, *p); return 0; }第一次运行前我先在纸上写p指向a[0]*p先取a[0]的值1然后指针移动到a[1]所以第一个printf输出1第二个printf里*p变成2。实际运行时如果输出顺序和你预想不一致就说明对“后置”的求值时机理解有偏差。二级C语言就喜欢考这类细节单独背语法规则容易忘跑一遍编译器印象会深很多。还要注意如果代码片段里有scanf、gets这些输入函数单独跑时要有输入数据。我的习惯是把输入写进一个文本文件运行命令改成./a.out input.txt这样每道题都能可重复验证。4.3 唐朔飞课后题与训练题混用的边界什么时候别迷信答案准备计算机考研的同学手边通常有唐朔飞《计算机组成原理》的课后题和这份训练题。这两类题可以一起做但心里要有数训练题是“考点扫描”唐朔飞的教材题是“原理推导”。扫描题往往只给结论推导题需要你从头写过程。混着刷时最忌讳的是把训练题答案当成绝对权威。举个常见的冲突点Cache的写直达法和写回法。有的训练题直接问“Cache更新主存的方式有哪些”答案列了一个“写直达”没有提“写回”。可唐朔飞的教材里这两种方案都会详细对比。如果你只是背了“写直达”这个词下次考试换个方式问“什么情况下写回法优于写直达”照样不会。所以我做这类题时只要训练题答案里出现“Cache”“主存”“写直达”这些词就会去翻教材把两种策略的适用条件抄在题目旁边。再比如“机器字长”的定义不同教材的用语略有差异。唐朔飞强调机器字长是CPU一次能处理的数据位数而某些训练题答案把存储器的位宽也扯进来结果两道题答案对不上。这种情况我以教材为准训练题答案标注为“有争议”。复习时不要浪费时间去背一个错误说法。如果备考的是软件设计师或其他计算机职业资格考试训练题里的组成原理部分同样可以作为基础练习但软考更偏体系结构、指令流水线和存储系统训练题里偏老的硬件常识题可以跳过。计算机程序设计员Java三级这类考试也会考计算机基础知识和C语言语法这份doc里的二级C语言段落当热身正合适。题目来源覆盖风格答案可靠度建议用法训练题doc碎、杂、考点面广中偶有印刷错误先扫描知识盲区唐朔飞课后题推导链完整高有教材依据重点章节精做真题/模拟题贴近考试角度高考前限时刷5. 避坑指南训练题doc的5个常见坑每个坑都能让你白折腾一晚上5.1 坑1公式和图片抽不出来的最大元凶是OLE对象现象用python-docx读取转换后的docx题目文本能拿到但数学公式全部变成空白或者图片位置只显示一个空段落。碰到“浮点数加减法”这类题题干缺了核心表达式根本没法判断选项到底在问哪个两个数相加。原因doc里的公式如果是由微软公式编辑器或MathType插入的真正的内容不在文本流里而在OLE对象里。python-docx主要读取w:t文本节点OLE对象以二进制形式嵌入在word目录下不暴露给paragraph.text。图片也一样doc里如果嵌入了WMF/EMF矢量图转成docx后虽然还挂着但python-docx默认不会把它转成可读文本。解决如果只是看题不追求文本抽取直接让LibreOffice把doc转成PDF公式和图片会以矢量或位图方式留在PDF里。命令很简单把--convert-to docx换成--convert-to pdf。如果一定要文本接受缺失把题干里的“______”当占位符公式部分手动补录。想自动提取公式目前只有把公式转成图片再用OCR识别成本高且对训练题来说不划算。5.2 坑2题号正则匹配错乱因为“第1题”和“1、”混用现象拆分脚本跑完题目数量少了三分之一。打开JSON一看有的题干被塞进上一题的body有的题号根本没出现。原因这份doc很可能不是一个人排的版。前面几章用“1、”后面几章用“第22题”还有的题号后面是中文全角句号“”。统计脚本里只用^(\d{1,3})[\.、\)]匹配遇到“第11题”就匹配不上这段文字就会当成普通文本追加到上一道题里。解决拆分前必须跑统计脚本并把它输出的所有编号格式都纳入正则匹配。正确的匹配顺序是先匹配第(\d)题再匹配(\d{1,3})[\.、\)]。因为“第11题”里的数字也可被第二个正则吃掉但如果先匹配中文格式就不会误拆。同时统计脚本里的.要写成\.否则“1a”这种也会被当成题号。全角句点“”的Unicode是UFF0E正则里直接写字面量编码工具一般都能识别。5.3 坑3直接用python-docx打开.doc报错“docx file invalid”现象明明文件名是训练题.docDocument(训练题.doc)却抛出PackageNotFoundError或者干脆报docx file invalid。原因python-docx的解析器完全依赖ZIP格式的docx结构而doc是OLE复合文档。它打不开doc不是代码不兼容是格式根本不支持。很多新手在这里卡壳以为是文件坏了其实是选错了工具。解决先做格式转换再用python-docx读。Windows下如果坚持用Word COM也不是不行$word New-Object -ComObject Word.Application $word.Visible $false $doc $word.Documents.Open(C:\temp\[详细完整版]计算机训练题.doc) $doc.SaveAs2(C:\temp\计算机训练题.docx, 16) $doc.Close() $word.Quit()这里SaveAs2的第二个参数16是wdFormatXMLDocument也就是保存为docx。COM方案的问题是Word版本不同枚举值可能变化而且服务器上COM权限经常抽风。LibreOffice的headless命令行更稳定推荐优先使用3.1节里的方案。记住任何需要批量处理的场景都不要走图形界面另存为。5.4 坑4文件损坏或页面异常一打开就转圈甚至系统重启现象双击doc后Word一直卡在“正在修复”界面几分钟后进程无响应个别老笔记本直接蓝屏重启。把文件拷到同事电脑上可能又能正常打开。原因文件在U盘拷贝或网盘下载过程中没有完整写入造成OLE2容器结构损坏。还有一种可能是文档里嵌入了损坏的OLE对象比如MathType公式的某个片段坏掉了Office渲染时触发崩溃。跟宏病毒不一定有关系但体验上像“中招了”。解决先别双击。用2.3节的Get-FileHash算一下文件大小和哈希如果大小只有几十KB基本可以判断不完整。然后用LibreOffice尝试转换libreoffice --headless --convert-to txt [详细完整版]计算机训练题.doc能转出txt说明文档主体还能读如果LibreOffice也卡住就说明容器本身坏得厉害。遇到这种情况只能找原始来源重新获取一份。我之前整理旧题库时遇到过一个“打开就重启”的doc后来发现是某道题里嵌入了一个损坏的Excel对象用LibreOffice转PDF绕过去才把题目看全。5.5 坑5Word自动编号导致复制粘贴后题目顺序错乱现象从训练题里挑选20道组成原理题复制到新文档后所有编号从“1、”重新开始。原来题干里的“第3题”字样不见了做Excel统计时匹配不上原题号。原因Word里的“编号列表”不是实实在在的文本而是一个自动编号域。复制粘贴到新文档时如果目标文档的列表模板也定义了自动编号新位置会按顺序重新生成。这种引用关系并不保留原来的题号语义。解决复制之前先全选CtrlA然后复制到新文档里右键选“粘贴为纯文本”或“只粘贴文本”。这样自动编号会落成普通字符格式可能会乱但题号不再是“活”的。对于做题库来说牺牲格式换取真实文本是划算的。粘贴后跑一遍3.3节的统计脚本如果还能识别出“1.”和“第X题”的数量就说明题号已经变成纯文本了。别直接CtrlV否则你会在刷题后台看到一堆“1、1、1、1”的假编号。6. 把训练题做成自测脚本用Python模拟考试环境并统计错题把题目拆进JSON之后这份训练题才真正算自己的。我最常用的自测脚本不到一百行。题库格式固定成这样{ id: 1, tag: 组成原理, question: Cache写回法与写直达法的主要区别是, options: {A: 每次写操作都更新主存, B: 只更新Cache, C: 写操作只写主存, D: 写操作同时更新主存和Cache}, answer: B }然后用random.sample随机抽20题答题后对错题累计import json import random with open(bank.json, encodingutf-8) as f: bank json.load(f) questions random.sample(bank, 20) score 0 wrong [] for q in questions: print(q[id], q[question]) for k, v in q[options].items(): print(f {k}. {v}) ans input(你的答案: ).strip().upper() if ans q[answer]: score 1 else: wrong.append((q[id], q[answer], ans)) print(f得分: {score}/{len(questions)}) print(错题ID:, [x[0] for x in wrong])脚本里的random.sample每次从题库里取不同题目适合模拟考试。如果想反复刷错题就改成只从wrong列表里选或者给每道题加一个wrong_count字段权重越高抽中概率越大。我自己的做法是当天用这20题模拟错题ID写进wrong_ids.txt第二天只从这些题里再抽10道直到正确率超过90%。这样做能明显减少盲目重复刷整卷的时间。最后一件事是我这些年整理训练题最深的教训别贪多先入库再刷题。早期我拿到训练题doc第一时间就是从头看结果看完就忘。后来改成先把题目结构化再按知识点归类最后用脚本自测一份几百题的文档只要一个晚上就能变成可复用的刷题系统。如果你也常跟旧版doc文件打交道建议把这个流程固定下来安全验货、转格式、拆题入库、分类自测。希望帮到你。本文还有配套的精品资源点击获取