
简介这是一份计算机专业基础习题汇编以选择题形式覆盖计算机发展史、冯·诺依曼体系结构、存储程序原理、计算机分类及应用领域等核心知识点适合高职与本科初学计算机、或备考期末/等级考试的读者用来自测与复习。包体为1个doc文档大小约415KB内容包含数十道经典选择题及参考答案部分题目后还附有知识解析可帮助理解数字量、二进制存储、各代计算机特征等易混淆概念。资源已有264人学习下载题目编排从宏观分类到微型机组成逐步深入通过反复练习可有效巩固计算机基础理论。对于需要快速梳理计算机常识的入门者这是一份轻量实用的刷题材料。1. 拿到一份 .doc 题库先别急着写正则处理“计算机专业习题-选择题.doc”这类文件通常不是打开 Word 复制粘贴那么简单。业务侧要的是把几百道选择题导入在线考试系统、刷题小程序或学习平台技术侧要面对的是 doc 老格式的二进制结构、不规则的题号编号、选项与题干混排、全角半角符号混杂。如果你上来就写一套解析脚本多半会在数据清洗阶段被各种边界情况拖住。这个标题的本质是一道“从存量 Word 文档中抽取半结构化数据”的工程题。它和传统爬虫或 JSON 解析不同doc 格式没有公开的简单文本接口选择题的排版也没有统一规范。本文会从 doc 格式的底层结构讲起给出一套能落地的解析方案——用 LibreOffice 完成格式转换再用规则引擎配合正则提取题目、选项和答案最后批量入库。适合需要处理历史题库的教育信息化工程师、做数据迁移的后端开发以及在自建考试系统里维护题库的运维人员。2. 先搞清 .doc 的老底为什么不能直接按文本读2.1 doc 与 docx 的本质区别.doc 是 Word 97-2003 使用的二进制文件格式基于 OLE2 复合文档结构。它把文本、样式、图片、表格分散存储在文件的不同扇区里文本内容按 Piece Table 组织而不是像 docx 那样是一个可以直接用 zip 解压、用 XML 解析的开放包格式。这意味着 python-docx、openpyxl 这类库对 doc 基本无效——它们只认 Office Open XML。对比项.docWord 97-2003.docxWord 2007底层结构OLE2 复合文档二进制ZIP 压缩包 XML文本存储Piece Table 分片存放document.xml 中按段落存储解析难度需专用库或转换可直接解压解析python-docx 支持不支持支持典型场景历史题库、老系统导出现代文档交换所以处理这类老文件第一原则是“不硬碰二进制”。直接用 POI 的 HWPF 去读 doc 确实可行但对文本提取、样式还原的精度要求较高且需要引入较重的 Java 依赖。更常见的做法是先转成 docx 或纯文本再进入规则解析阶段这样能把格式解析和内容抽取两个问题拆开处理。2.2 选择题文档里常见的三种排版套路在动手写解析代码之前先要观察源头文档长什么样。虽然标题叫“计算机专业习题-选择题.doc”但实际文件里的排版往往不是一份干净的规范文档。我把历次接手过的类似题库归纳为三种模式模式 A题干连续选项独立成段。这是最理想的排版。题号“1、”后跟题干回车然后 A、B、C、D 四个选项各占一行。答案可能跟在题后也可能集中放在文末。模式 B题干与选项在同一行。例如“1. 以下哪种排序算法时间复杂度为 O(n log n)A. 冒泡 B. 快排 C. 插入 D. 堆排序”。这种模式最头疼因为题干和选项之间没有明确的换行边界。模式 C混合排版。前面几十题是模式 A中间插入图片题、多选题、判断题后边又变成模式 B。这种文档占真实题量的四成以上。解析方案的设计必须同时覆盖这三种模式而且不能被“看起来统一”的表象骗了。下面给出的代码就是基于“先转换、再按行扫描、最后用状态机聚合”的思路而不是依赖单一正则一把梭。3. 用 LibreOffice 批量转换从 doc 到 docx 的最小代价路径3.1 为什么选 LibreOffice 而不是在线转换工具在线转换工具不适合批量处理。一份题库可能有几十个 doc 文件逐个上传下载效率低而且涉及学生考试数据不建议把文件传到第三方服务。LibreOffice 的 headless 模式可以在命令行完成格式转换安装一次就能在服务器上长期跑。它比 antiword 和 catdoc 的兼容性更好能把样式、表格、页眉页脚一起带过去比直接调 Word COM 对象更省资源不需要 Windows 环境Linux 服务器上也能稳定运行。在 Ubuntu 或 CentOS 上安装后先验证 soffice 命令可用soffice --headless --convert-to docx --outdir /data/task/converted /data/task/raw/计算机专业习题-选择题.doc这条命令把指定 doc 文件输出为 docx放在 converted 目录下。--headless表示不启动图形界面--convert-to docx指定输出格式--outdir是输出目录。如果文档很多可以写成循环mkdir -p /data/task/converted for f in /data/task/raw/*.doc; do soffice --headless --convert-to docx --outdir /data/task/converted $f done注意LibreOffice 一次处理多个文件时最好不要并行执行因为同一用户下的 soffice 实例会竞争用户配置文件可能出现“已在运行”的报错。批量转换时建议串行或用-env:UserInstallationfile:///tmp/lo_profile_$PID为每个进程指定独立配置目录来并行。3.2 转换完成后先做一次人工抽检转换不是终点只是解析的起点。转出来的 docx 要用 python-docx 快速读一遍段落数和文本长度和原文件做个粗对比from docx import Document doc Document(/data/task/converted/计算机专业习题-选择题.docx) paras [p.text.strip() for p in doc.paragraphs if p.text.strip()] print(f非空段落数: {len(paras)}) for p in paras[:10]: print(p[:80])如果发现段落数和原文件差异过大可能存在两种问题一是源 doc 里有文本框或浮动对象转换后内容变成了单独的文本框节点Docx.paragraphs读不到二是全角空格或制表符在转换过程中被替换成了普通空格导致行首的题号前缀变了。抽检能看到这些异常而不是直接闷头写解析规则。4. 解析选择题状态机 正则的混合方案4.1 先把判断题号和选项的正则写稳转换完成后解析 docx 里的段落文本。核心是识别三类行题号行、选项行、答案行。import re PATTERN_QUESTION re.compile(r^\s*(第?\s*[0-9一二三四五六七八九十百]\s*[题、.:)]\s*)) PATTERN_OPTION re.compile(r^\s*([A-Ha-h])\s*[.、:)]\s*) PATTERN_ANSWER re.compile(r(?:答案|参考答案|正确答案)\s*[:]?\s*([A-Ha-h]))PATTERN_QUESTION匹配“1、”“1.”“第1题”“1)”等常见题号格式[、.:)]中的字符集覆盖了中文输入法和英文输入法的差异。PATTERN_OPTION匹配 A-H 选项前缀兼容半角句号、顿号、全角句号、冒号和括号等分隔符。PATTERN_ANSWER匹配答案解析行用[:]?忽略可选冒号答案区可能有多选如“ABCD”。写正则时最容易犯的错是过度追求一次匹配整道题。题目、选项、答案可能分布在多个段落里比如选项和答案之间隔了一个空段落或一张图片单条正则无法覆盖这种间隔。所以解析器应该按行扫描、按状态流转。4.2 状态机主循环下面这个函数将 docx 段落列表解析成一个题目字典列表def parse_choice_questions(paragraphs): questions [] current None for line in paragraphs: line line.strip() if not line: continue m_q PATTERN_QUESTION.match(line) if m_q and not PATTERN_OPTION.match(line): if current: questions.append(current) current { question: line[m_q.end():], options: [], answer: , raw: line, } continue m_o PATTERN_OPTION.match(line) if m_o and current is not None: current[options].append({ key: m_o.group(1).upper(), text: line[m_o.end():], }) continue m_a PATTERN_ANSWER.search(line) if m_a and current is not None: current[answer] m_a.group(1).upper() continue if current is not None and not m_q: # 题干续行比如题干过长被 Word 自动换行后的第二行 if not current[options]: current[question] line else: # 选项行中间夹了说明文字忽略或追加到最后一个选项 current[options][-1][text] line if current: questions.append(current) return questions逻辑说明当遇到题号行且该行不是选项行时认为新题开始之后遇到选项行则加入当前题的options列表遇到“答案”字样则填入answer字段。对于既不是题号也不是选项的文本行若当前题还没有任何选项则视为题干续行并追加到题干文本中若已有选项再遇到杂散文本则追加到最后一个选项文本后尽量减少信息丢失。这段代码能覆盖模式 A 和大部分模式 C。如果是“题干和选项同一行”的模式 B就需要在题号行内继续拆分选项——在m_q分支里用PATTERN_OPTION在行内搜索if m_q: inline_options list(PATTERN_OPTION.finditer(line)) if inline_options: # 题干结束于第一个选项之前 current[question] line[m_q.end():inline_options[0].start()] for i, m in enumerate(inline_options): end inline_options[i 1].start() if i 1 len(inline_options) else len(line) current[options].append({ key: m.group(1).upper(), text: line[m.end():end].strip(), }) # ...后续正常处理这段内联逻辑先用finditer找出行内所有“A.”、“B.” 这样的选项起点题干取题号结束到第一个选项起点之间的文本每个选项文本取当前选项结束到下一个选项起点之间的内容。这样模式 B 也能解析。4.3 答案缺失怎么补很多 doc 题库不把答案写在题目后面而是集中放在文档末尾的“参考答案”章节。这种情况要先扫描全文定位答案区建立“题目序号 - 答案”的映射再回填到解析结果里m re.search(r(?:参考答案|答案|标准答案)[:]?\s*(.*)$, full_text, re.S) if m: answer_block m.group(1) pairs re.findall(r(\d)\s*[.、:)]?\s*([A-Ha-h]), answer_block) answer_map {int(num): ans.upper() for num, ans in pairs} for q in questions: num PATTERN_QUESTION.match(q[raw]).group(1) q_num int(re.sub(r[^0-9], , num)) if re.search(r\d, num) else None if q_num and q_num in answer_map: q[answer] answer_map[q_num]这个方案只适用于答案区编号是数字的情况如果原文档用“一、选择题”后接答案或者答案区连题号都没有只按顺序排列就需要用游标计数的方式按顺序回填。这两种情况可以写成一个分支优先按题号映射匹配不到时按顺序。5. 批量入库把解析结果写进考试系统5.1 表结构设计与批量插入解析完成的题目要入库。如果考试系统的题库表结构可以自定义建议至少包含这些字段字段类型说明idBIGINT UNSIGNED自增主键subject_idINT科目编号如“计算机基础”1question_typeTINYINT1单选2多选contentTEXT题干文本option_a ~ option_hVARCHAR(255)选项文本按需使用answerVARCHAR(8)答案如“ABD”difficultyTINYINT难度等级1-5source_fileVARCHAR(128)来源文件名方便回溯created_atDATETIME入库时间使用 MySQL 8.0 的参数化批量插入避免 SQL 注入并按批提交import pymysql conn pymysql.connect(host127.0.0.1, userquiz_writer, passwordpwd, databaseexam_db) sql INSERT INTO question_bank (subject_id, question_type, content, option_a, option_b, option_c, option_d, answer, difficulty, source_file) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s) batch [] for q in parsed_questions: opts {o[key]: o[text] for o in q[options]} batch.append(( 1, # 科目编号 2 if len(q[answer]) 1 else 1, # 根据答案长度判断多选 q[question], opts.get(A, ), opts.get(B, ), opts.get(C, ), opts.get(D, ), q[answer], 3, # 默认难度 source_file, )) if len(batch) 100: with conn.cursor() as cursor: cursor.executemany(sql, batch) conn.commit() batch.clear() if batch: with conn.cursor() as cursor: cursor.executemany(sql, batch) conn.commit() conn.close()这里的批大小设为 100 是一个折中值——太小则事务提交次数多太大会导致单条 SQL 包过大。如果题目含大量长文本建议把批大小降到 50 并监控网络包尺寸。5.2 入库后的幂等校验题库系统最怕重复导入。一个简单的幂等方案是给content字段加 MD5 散列或者在源文件里用“文件名 题号”作为唯一键。更可靠的方案是对题干做规范化后再算 hashimport hashlib def question_hash(text): norm re.sub(r\s, , text).lower() return hashlib.md5(norm.encode(utf-8)).hexdigest()插入前先查一遍 hash已存在的题直接跳过或标记为“重复”。hash 粒度是整道题只改一个选项不会影响题干 hash这个粒度适合大多数场景如果连选项改动也要感知就把题干和选项文本拼起来再 hash。6. 最后一公里doc 转 docx 后的三个隐性坑和几个实用技巧6.1 修订模式导致的文本重复老 doc 文件里有可能开着“修订”模式。转换后 docx 的段落文本会同时包含删除线和插入内容比如“计算机应用基础”这种视觉上不直观的重复。解析时如果发现题干的文本量明显异常可以在提取前去掉修订痕迹。理想做法是在 Word 里先“接受全部修订”但如果批量处理做不到可以在转换时报错后单独处理问题文件而不是试图用代码去理解修订标记的语义。提示解析结果里题干出现连续重复片段时优先检查源文件是否处于修订状态——这不是代码 bug是源数据问题。6.2 编码陷阱GBK 与 UTF-8 的隐性冲突docx 内部是 UTF-8转换过程一般不会丢字符。但如果中间从 doc 先转成 txt 再读就极可能在 Windows 环境下遇到 GBK 错乱的问题。所以不建议“doc - txt - 解析”的中间链路尽量直接“doc - docx - python-docx”。如果实在只能拿到 txt读文件时用open(path, encodinggbk, errorsreplace)并统计替换次数快速判断编码是否匹配。6.3 一个值得留存的技巧先做段落聚合再走状态机有些 doc 里的题干不是按逻辑段落换行而是每个 10 到 20 个字符就有一个软回车垂直制表符或手动换行符。这种文档的直接后果是解析出的“题干”只有半行文字。我一般会在进入状态机之前先把相邻段落中“行尾没有终止标点且下一行不是选项行”的文本合并形成完整的逻辑段落再做题目识别。merged [] for p in paragraphs: text p.strip() if not text: continue if (merged and not text[0].isdigit() and not PATTERN_OPTION.match(text) and not merged[-1].endswith((。, , ?, ., , :))): merged[-1] text else: merged.append(text)这个合并规则的核心思想是“语义止损”前一段没有句号结尾后一段又不是新题目的开头那就判定为同一逻辑段落。宁可少合并也不多合并因为多合并会把两道相邻但没空行的选择题并到一起而少合并最多导致题干缺字后续还有补救空间。合并之后再把merged喂给第 4.2 节的状态机能在不改变正则规则的前提下显著提升解析正确率。这个技巧对从老系统导出的、排版零散的 doc 文件尤其有效——你可以先拿一个文件试跑对比合并前后的解析结果通常正确率能从 70% 提到 90% 以上。本文还有配套的精品资源点击获取