ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从 .doc 到结构化题库:选择题文档解析与 JSON 转换全流程

从 .doc 到结构化题库:选择题文档解析与 JSON 转换全流程 简介这份习题集为计算机专业基础课程提供了典型选择题训练面向本科、高职、自考等阶段的初学者与备考者可用于章节自测或考前速记。文档以1个doc文件打包整体仅415KB轻量便于下载后打印或导入笔记软件使用。全部题目围绕计算机发展脉络展开涵盖电子数字计算机的分类、ENIAC的历史地位、冯·诺依曼体系结构五大部件、各代计算机逻辑器件与存储器变迁、计算机应用领域科学计算、数据处理、实时控制等以及微型机软硬件基础等核心知识点。每题后直接标注正确答案部分题目附简要解析能够帮助读者快速定位知识薄弱环节巩固选择题易考易混的细节。资源已有264人学习浏览适合考前突击或日常碎片化复习。1. 一份选择题.doc卡住的往往不是题目拿到「计算机专业习题-选择题.doc」这类文档大部分人的第一反应是双击打开、复制粘贴、整理成 Excel 或导入刷题系统。但真到落地阶段你会发现麻烦全在“看不见”的地方老版本 .doc 的二进制格式、段落里混排的自动编号、答案换个位置写法就完全不同的结构。计算机专业课的题库往往是课程组一届一届传下来的题目没问题格式却可能跨越了 Word 97 到 WPS 的多个时代。这篇文章会从 .doc 的格式兼容问题讲起到选择题结构的自动切分、答案匹配与对账最后落地成一份可直接入库的 JSON。整个过程适用于所有以选择题为主的题库类文档尤其是含大量代码片段、英文术语的计算机专业课习题。2. 把 .doc 读出来的三条路径格式兼容与编码坑2.1 为什么 python-docx 直接打开 .doc 会报错常见的办公文档处理库比如 python-docx只支持 .docx 格式。.doc 是 OLE2 复合文档结构而 .docx 是 ZIP 包内的 XML 文件集合两者底层完全不同。直接拿 python-docx 去读一个老 .doc通常会抛出一个找不到 word/document.xml 的异常。这个问题的本质不是代码写的对不对而是容器格式根本不对。所以在处理「计算机专业习题-选择题.doc」之前第一步永远是格式转换或底层解析。常见的路径有三条我按优先级梳理如下。路径工具适用场景主要限制无头转换LibreOffice / soffice批量处理、保留排版需要安装 LibreOffice纯文本抽取antiword只关心文字内容图表、公式全部丢失底层解析olefile 手动解析 WordDocument 流特殊格式研究工作量大不推荐2.2 首选方案LibreOffice 无头转换 doc → docx常见做法是安装 LibreOffice用它的命令行无头模式把 .doc 批量转成 .docx再用 python-docx 读取。转换命令长这样soffice --headless --convert-to docx --outdir ./converted 计算机专业习题-选择题.doc这条命令的核心参数有三个。--headless表示不启动图形界面适合在服务器上跑--convert-to docx指定目标格式--outdir指定输出目录。转换完成后在converted目录下会生成同名.docx文件此时再用 python-docx 打开就不会报错了。如果你有几十份类似的 .doc 文件可以直接写个循环批量处理for f in *.doc; do soffice --headless --convert-to docx --outdir ./converted $f done要注意的是LibreOffice 转换对中文文件名支持良好但如果原文档里嵌入了老旧的公式编辑器对象比如 MathType 3.x转换成 docx 后公式可能变成图片这会影响后续的文本提取。计算机专业课习题里常见程序运行结果、进制转换这类纯文本题目转换后基本不会丢失内容。2.3 备用路径antiword 直接抽文本如果只是想把文本内容捞出来看个大概不关心格式和排版antiword 是个更轻量的选择antiword 计算机专业习题-选择题.doc output.txtantiword 的输出是纯文本题号和选项内容都能看到但缺点是它不处理表格、文本框和图片。如果文档里有用文本框排版的选择题antiword 抽出来的内容顺序可能会乱。我一般拿 antiword 做快速预览正式处理还是走 LibreOffice 转 docx 再解析的路线。提示转换后一定要抽查转换结果。打开生成的 .docx 确认题目顺序、段落编号、代码缩进没有丢失再进行下一步的解析。2.4 中文编码乱码的处理.doc 里的中文文本存储有 ANSI 和 Unicode 两种可能。老版本 Word 存的是 GBK/GB2312新版本可能存 UTF-16LE。用 antiword 抽文本时如果看到乱码多半是编码参数不对antiword -m cp936.txt 计算机专业习题-选择题.doc现代 Linux 发行版的 antiword 通常自带 cp936 映射文件找不到时需要手动指定映射路径。如果走 LibreOffice 转 docx 的路线编码问题基本被透明处理掉了这也是我优先推荐它的原因。3. 选择题结构切分题号、选项与段落噪点3.1 用正则把题干段落切成题目块转换成 docx 之后题目内容以段落形式存在。解析选择题的第一步是把连续的段落按题号切分成一个个独立题目块。计算机专业习题的题号格式比较常规常见的有1.、1、、1全角句点等但偶尔也有第1题这种带文字的格式。我一般用正则做两段匹配先匹配题号再匹配选项。下面是核心切分代码import re from docx import Document doc Document(计算机专业习题-选择题.docx) paragraphs [p.text.strip() for p in doc.paragraphs if p.text.strip()] question_pat re.compile(r^(\d{1,3})\s*[\.、、)]) option_pat re.compile(r^([A-H])\s*[\.、、)]\s*(.*)) questions [] current None for line in paragraphs: qm question_pat.match(line) if qm: if current: questions.append(current) current { qid: int(qm.group(1)), stem: line, options: [], answer: None } else: if current is None: continue om option_pat.match(line) if om: current[options].append({ key: om.group(1), content: om.group(2) }) else: current[stem] \n line if current: questions.append(current) print(f共解析到 {len(questions)} 道题目)这段代码的逻辑分三层。第一层用question_pat匹配题号开头的段落一旦命中就新建一个题目块第二层用option_pat匹配 A.、B.、C. 这类选项开头第三层处理题干跨多段的情况即既不是题号也不是选项的行直接追加到当前题干的正文里。正则里的[\.、、)]覆盖了半角句点、顿号、全角句点和括号的多种书写习惯。计算机专业课的习题里常出现“以下程序运行结果是”这种短题干占一行、选项跟后面的排版上面的代码可以正确处理。3.2 多选题、判断题与无选项题目的边界计算机专业的选择题不全是单选常见的变形有三种多选题、判断题、填空题。多选题的选项和单选一样是 A-D 甚至 A-F但答案不只一个判断题往往没有 ABCD 选项题干直接是“正确”或“错误”的陈述填空题则根本没有选项结构。多选题在结构上和单选无差异区分点全在答案内容的长度上。判断题则需要在解析时做特殊识别judge_pat re.compile(r^[(]\s*([√×])\s*[)])如果一行命中这个模式说明这是判断题答案而不是选择题的选项行。遇到这种情况可以直接把题干标记为判断题不期望后续出现选项。切分代码里需要注意判断行的选项匹配不能意外吞掉题干文本否则后续的答案匹配会对不上号。3.3 自动编号带来的整段丢失问题这是最容易踩的深坑。Word 里的“自动编号”不是真实文本而是 WordprocessingML 里的w:numPr结构。如果你在 python-docx 里通过p.text读取题号可能吞掉也可能和文本拼在一起成一个怪字符串。w:p w:pPr w:numPr w:ilvl w:val0/ w:numId w:val1/ /w:numPr /w:pPr w:rw:t在操作系统中进程和程序的主要区别是/w:t/w:r /w:p上面这段 XML 里题号“1.”是自动编号生成的段落文本里只有题干内容。按 3.1 的正则切分时这个段落匹配不到题号会被当成题干续行导致和前面的题目块合并最终题目数量变少。处理办法是当正则匹配不到新题号但这个段落格式和上一段明显分属不同题目时需要检查段落的numPr信息。python-docx 对numPr的原生支持有限但可以通过p._p.pPr手动访问 XML。遇到这种文档我一般直接绕回 LibreOffice用转换后的文档跑一遍逐段检查把自动编号落成真实文本再解析。4. 答案区域定位与匹配对账4.1 三种常见的答案书写习惯切分出题目结构后最麻烦的一步是怎么把答案对应到题号上。计算机专业习题的 .doc 里答案的书写习惯基本是三种。第一种是题末内联格式为“答案C”或者“【答案】C”紧跟在选项后面第二种是集中答案区文档末尾有一段连续的区域格式通常是“1-5B A C D B”或者“1.B 2.C 3.A”第三种是带解析的混合型题目后面跟着答案和解析比如“答案C解析进程是资源分配的最小单位”。第三种最容易处理答案和题干在同一个题目块内。第一种需要先定位题目块结尾再匹配答案关键字。第二种最难因为集中答案区往往不分段落一长串答案挤在一起。4.2 答案匹配的核心代码以下代码处理题末内联答案和文件末尾集中答案区两种场景import re inline_ans re.compile(r[答案|参考答案][:]\s*([A-H])) # 处理内联答案 for q in questions: m inline_ans.search(q[stem]) if m: q[answer] m.group(1) # 处理集中答案区 concentrated_pat re.compile(r(\d{1,3})\s*[\.、]\s*([A-H])) concentrated_answers {} for p in doc.paragraphs: text p.text.strip() if 答案 in text and re.search(r\d{1,3}, text): for match in concentrated_pat.finditer(text): concentrated_answers[int(match.group(1))] match.group(2) for q in questions: if q[answer] is None: q[answer] concentrated_answers.get(q[qid])上面这段代码先扫描题目内联答案优先匹配“答案”或“参考答案”后跟冒号和字母的格式接着找出包含题号的段落用finditer把所有“题号 答案字母”的配对提取成字典最后对于没匹配到内联答案的题目去字典里查它的题号。re.finditer比re.search更适合集中答案区因为文档里常有“1.B 2.C 3.A”这种一行多个配对的情况search只取第一个finditer全部捞出。提示集中答案区匹配到的题号数如果远小于题目总数多半是答案区的题号和题目区的题号格式不一致。比如题目区消耗“1.”半角句点答案区用“1、”顿号正则里必须用[\.、]字符类统一兼容。4.3 对账失败时先查这四个位置跑完答案匹配后必须对账。最简单的方法是统计“有答案的题目数”和“总题目数”如果不等优先查四个位置。第一个是题干里包含答案字样。有些题目本身的题干就写着“以下哪项不是……”如果解析时把“答案”当作内联答案就会错配。这种情况需要限制内联答案的匹配位置比如要求“答案”必须出现在最后一个选项之后。第二个是选项漏切导致答案挂在题干里。第三个是自动编号导致的题号错位答案区对不上题号。第四个是选择题和判断题混排判断题答案画的是“√/×”而不是 ABCD切分后答案字段一直填不上。对账代码建议这样写missing [q[qid] for q in questions if q[answer] is None] print(f缺失答案的题目{missing})如果缺失的题号呈连续分布比如 12-18 题全缺基本可以断定是文档中间某段格式突变比如 12 题开始选项变成了“① ② ③”的序号而非 ABCD。此时需要回到原始 .doc人工确认该区间的真实格式。5. 批量跑通从 .doc 到结构化题库 JSON处理一份「计算机专业习题-选择题.doc」不复杂但如果是一个课程组的题库文件夹几十份文档、几千道题就得把流程串成一个脚本。我的做法是把上一章的解析函数整理成parse_doc_to_questions(docx_path)再加上全目录遍历和 JSON 导出。import os import json import subprocess from docx import Document def convert_doc_to_docx(doc_path, out_dir): subprocess.run( [soffice, --headless, --convert-to, docx, --outdir, out_dir, doc_path], checkTrue, capture_outputTrue ) def process_folder(src_dir, tmp_dir, output_path): all_questions [] for fname in os.listdir(src_dir): if fname.endswith(.doc): docx_path convert_doc_to_docx( os.path.join(src_dir, fname), tmp_dir ) questions parse_doc_to_questions(docx_path) all_questions.extend(questions) with open(output_path, w, encodingutf-8) as f: json.dump(all_questions, f, ensure_asciiFalse, indent2) process_folder(题库原始文件, 临时转换目录, 题库输出.json)process_folder函数做的事很简单遍历源目录下所有 .doc 文件逐个转成 docx 再解析最后把所有题目合并导出成一个 JSON 数组。JSON 里的每个题目对象包含题号、题干、选项列表和答案字段后续要导入刷题平台、排版新试卷或做知识点标注都可以基于这个结构继续扩展。最后的验证环节我会从导出的 JSON 里随机抽 5 道题逐条对照原始 .doc 的排版确认题干完整、选项顺序正确、答案对应无误。对于最终落到在线刷题系统的数据还可以额外跑一遍答案合法性校验多选题答案里的字母必须按升序排列答案字母必须在 A-F 范围内题号必须连续且不能有重复这些规则用一次遍历就能完成核查。题库整理到此才算真正收口。本文还有配套的精品资源点击获取
返回列表