拓冰建站拓冰建站
首页 / 资讯中心 / 正文

从docx提取数学建模题目与答案:Python全流程解析

简介这份数学建模学习资料以 8 页 docx 文档收录了多道典型建模题目及详细解答覆盖方桌稳性证明、委员会名额分配、生猪出售时机、奶制品生产计划等经典案例适合数学建模竞赛初学者、高校相关课程学生及需要快速上手建模方法的自学者。资源包仅有 1 个 docx 文件大小 207KB内容紧凑便于直接阅读、打印或二次排版。目前已吸引 88 人学习浏览。文档不仅给出每道题的数学模型与求解过程还通过连续函数介值定理、比例分配法、二次函数最值、线性规划等展示了从问题剖析、假设设定到结果验证的完整思路可帮助读者理解如何处理约束条件与灵敏度分析并在练题中提升逻辑推理和优化决策能力。对于想要短时间熟悉常见建模题型和答题规范的人来说是一份实用的入门级参考资料。1. 数学建模题目与答案的docx第一步不是做题而是拆文档拿到“数学建模学习资料 数学建模题目及答案 共8页.docx”这类文件很多人第一反应是打开、复制、做题。等真正把题目存进自己的笔记或者安排进学习计划时才发现问题集中在另一面题目里的数学公式粘出来就成乱码答案和题目之间没有分页8页内容在Word里看着整齐换到Markdown或者网页里就错位。对经常整理资料、做自动化复习工具的IT从业者来说学习资料的价值取决于能不能被结构化复现而不是能不能打开。这篇从docx的文件结构讲起落到一套“提取题目和答案建立本地题库查询”的完整路径让你以后碰到类似的数学建模资料都能直接套用。2. 先拆docx的壳再谈数学建模题目的结构化提取2.1 docx是zip不是纯文本解析先看word/目录先说一个反直觉的结论docx本质上不是文本文件而是一个zip压缩包。拿记事本打开会看到一堆乱码那是正常现象因为正文真实存放位置是压缩包里的word/document.xml。公式图片在word/media/嵌入的公式编辑器对象在word/embeddings/这三个路径是解析数学建模题目时最先要确认的东西。先跑一次文件探测确认手头的文件到底是不是标准docx。很多网上下载的“数学建模题目及答案”只是套了个docx后缀实际是旧版doc甚至是HTML改的扩展名。doc数学建模学习资料 数学建模题目及答案 共8页.docx file $doc unzip -l $doc | grep -E word/(document|media|embeddings)第一行file输出文件的真实类型第二行用unzip -l列出压缩包内部结构不实际解压速度很快。如果命令报zipinfo: cannot find zipfile directory基本可以断定这个docx是伪造的后面所有基于python-docx的处理都做不了。注意文件名里的空格和中文变量一定要用双引号包住否则shell会把文件名拆成多个参数。这个细节在处理从微信、飞书下载的资料时尤其容易翻车。数学建模学习资料有一个天然优势内容结构比普通散文清晰得多。题干固定包含问题描述、建模要求、求解目标答案部分通常以“参考答案”或“解”开头。这种结构决定了后续可以靠状态机切分但前提是先把格式层面的坑全部绕开。2.2 用python-docx快速盘点8页文档的段落和表格确认文件确实是docx之后先用python-docx做一次全量盘点。这一步的目标不是抽取题目而是搞清楚这份只有8页的资料里题目到底是写在段落里还是写在表格里公式插入方式是什么。盲目直接抽取后面很容易丢字段。from docx import Document doc_path 数学建模学习资料 数学建模题目及答案 共8页.docx doc Document(doc_path) print(段落总数:, len(doc.paragraphs)) print(表格总数:, len(doc.tables)) for i, p in enumerate(doc.paragraphs[:60]): text p.text.strip() if text: print(i, p.style.name, text[:50])doc.paragraphs拿的是正文段落doc.tables是文档里的表格对象。遍历前60段时看两个字段一是p.text是否有内容二是p.style.name的样式名。很多数学建模题目用手动编号样式清一色都是Normal如果发现样式名里有Heading或者List Paragraph后面抽取时就可以考虑把它也作为锚点候选。如果打印结果显示段落总数很少但表格总数很多说明题目内容是嵌在表格单元格里的。单元格文本要通过cell.text取得不能靠段落遍历。比如参考答案里给了一个参数对照表表格里既有文字又有数据这种内容在后续抽取时建议单独存一个字段不要和普通段落混在一起。2.3 数学建模资料里的三类排版陷阱公式、表格、手动编号这8页资料里最影响文本抽取的不是题目难度而是三个排版坑OMML公式、表格混排、手动编号。陷阱类型识别特征对抽取的影响处理思路OMML公式段落text为空但document.xml里有m:oMath节点直接丢题干或答案中的数学表达式从XML里提取公式节点转图片或LaTeX表格混排题干或答案写在表格单元格里只遍历paragraphs会少一半内容对tables做单元格级解析再拼回到题目正文手动编号题号写成“1、”“问题一”不是Word自动编号按样式过滤题号会全部丢失用正则匹配文本前缀不依赖style识别方法也不复杂。公式段落一般在python-docx里表现为p.text是空字符串但段落里并不是真的空而是嵌入了数学对象表格陷阱则要靠doc.tables的遍历去发现。手动编号最坑看起来段落里都有文字但样式全是正文导致很多按样式过滤的抽取脚本在这里失效。3. 用状态机切分“题目”和“答案”落到JSON3.1 先按数学建模题目的常见写法定锚点规则要抽“数学建模题目及答案”得先定义什么叫一道题、什么叫答案。数学建模资料里题目部分经常出现“问题1”“请建立数学模型”“题目一”这类文字答案部分则是“参考答案”“解析”“解”。这些就是切分锚点。定义锚点我用正则不用文本包含判断因为文档里的手写编号格式不稳定正则可以在一个规则里覆盖多种写法。import re question_anchor re.compile( r(^|\s)(问题\s*[一二三四五六\d]|题目\s*\d|Problem\s*\d), re.I, ) answer_anchor re.compile( r(参考答案|参考解答|解析|答案|解[:]) )question_anchor用(^|\s)限制题号必须出现在行首或者空格之后避免正文里写到“这个问题需要解决”时被误判成新题。answer_anchor里的“解”适合建模题那种带详细推导的答案但如果文档里题干也出现“解析”这类词需要再根据上下文调整。如果发现8页文档的答案区域有固定颜色或者固定缩进样式也可以把p.style.name加进锚点判断。样式锚点比文本锚点更稳定但前提是整份资料是同一个模板生成的从网上下载的大杂烩文档很难满足。3.2 用状态机遍历段落的抽取代码锚点定义好之后用一个三态状态机遍历所有段落。之所以用状态机而不用简单的if/else是因为一套题包含“题干多段 答案多段”的结构状态可以保证切分的连续性。records [] state waiting item None for p in doc.paragraphs: text p.text.strip() if not text: continue if question_anchor.search(text): if item is not None: records.append(item) item {title: text, question: [], answer: []} state question continue if answer_anchor.search(text) and item is not None: state answer item[answer].append(text) continue if item is not None: if state question: item[question].append(text) elif state answer: item[answer].append(text) if item is not None: records.append(item) print(抽到题目/答案块数:, len(records))状态机的三个枚举值是waiting、question、answer。waiting表示还没遇到第一道题遇到question_anchor时把当前题目的临时记录封存新建一条记录遇到answer_anchor时把状态切到answer区后续段落全部归入答案数组。用continue跳过锚点行本身防止“问题1”这四个字混进题干内容。抽取后需要检查len(records)是否和原文档实际题号一致。如果抽出数量明显少于预期优先检查是不是某道题用了“1、”这种没有被正则应进去的编号如果答案数量对不上多半是answer_anchor没匹配到最终的“参考答案”段落。3.3 将结果输出JSON并保留题库的唯一ID切分完成后把结果写入JSON文件并且为每道题生成一个唯一的id。import json for idx, r in enumerate(records, start1): r[id] fmath_2024_{idx:03d} with open(math_modeling_questions.json, w, encodingutf-8) as f: json.dump(records, f, ensure_asciiFalse, indent2) print(已写出 JSON 文件)ensure_asciiFalse让中文字符原样写入indent2保证文件打开时仍然有可读性。id字段用“math_2024_001”这种命名方式是为了后续导入SQLite时直接当主键。数学建模题目经常出现多个“问题1”如果拿标题当唯一标识数据库里必然撞主键。4. WPS兼容与docx变体读不到内容时的三层排查4.1 扩展名是docx不代表真的docx从网上下载或者从聊天工具里转存的“数学建模学习资料 数学建模题目及答案 共8页.docx”经常遇到扩展名是docx实际文件是老版doc或HTML改名。Word和WPS打开时能自动识别但python-docx不认直接用Document()打开会直接报错。最稳妥的办法是在解析之前先做文件探测。file 数学建模资料.docx xxd 数学建模资料.docx | head -5xxd看文件头两个字节最直接。标准docx文件头是PK也就是十六进制的50 4B。如果看到D0 CF 11 E0这是OLE复合文档属于老版doc如果看到3C 68 74 6D 68说明是HTML文件。这两种情况都要先让用户在WPS里打开再另存为标准docx。另存时注意不要选“启用宏的docx”python-docx解析不了带宏的文件。这里就是wps 不能默认新建 docx最容易暴露的位置WPS默认新建的文档格式不一定是docx导致团队成员交上来的文件格式五花八门最后全堆到你手里做二次处理。4.2 用zipfile直接检查document.xml和命名空间如果文件头没问题python-docx还是报“Package not found”可以跳过第三方库用Python标准库直接检查压缩包内容。import zipfile doc_path 数学建模学习资料 数学建模题目及答案 共8页.docx with zipfile.ZipFile(doc_path) as z: names z.namelist() print(压缩包内文件数量:, len(names)) if word/document.xml in names: xml z.read(word/document.xml).decode(utf-8, errorsreplace) print(document.xml 长度:, len(xml)) print(含OMML公式:, m:oMath in xml) else: print(缺少word/document.xml不是标准docx)核心是看word/document.xml是否存在。有些手机版Office压缩出来的目录大小写不标准或者多套了一层目录z.namelist()能直接暴露真实情况。打印“含OMML公式”是为了确认这份数学建模资料里的公式是否以标准OMML形式存在如果是MathType或者图片公式后面抽取时就要走另外一套方案。这种检查方式还有一个额外价值可以判断文档是否处于加密状态。加密过的docx文件document.xml内容通常是乱码或者不可读解析出来的XML长串里会出现大量不可见字符这时候需要让文档作者去掉密码保护。4.3 wps不能默认新建docx的默认格式坑在工作流里经常遇到同事用WPS新建文档并直接保存默认格式不是docx导致收集上来的“数学建模资料.docx”实际无法被程序解析。WPS的设置项一般在“设置 - 通用与存储 - 文件格式”里把新建文档的默认格式改成docx。如果源头文件已经生成批量检查可以用一条bash命令把所有疑似伪docx的文件挑出来。for f in *.docx; do if ! unzip -l $f /dev/null 21; then mv $f ${f%.docx}.bak echo 疑似伪docx: $f fi done这条命令把所有用zip协议打不开的docx文件改名成.bak避免后续处理时中断整个脚本。unzip -l的退出状态码可以作为判断依据能列出文件内容就说明是标准zip结构。改名之后通知来源方用WPS重新另存为标准docx再放回目录继续处理。5. 把题库导入SQLite答题状态与模糊检索一次做完5.1 从JSON导入SQLite并建表JSON只是中间格式更实用的做法是把题库导入SQLite这样之后可以用SQL做筛选、统计、随机抽题。import sqlite3, json conn sqlite3.connect(math_modeling.db) cur conn.cursor() cur.execute(DROP TABLE IF EXISTS questions) cur.execute( CREATE TABLE questions ( id TEXT PRIMARY KEY, title TEXT, question TEXT, answer TEXT, status TEXT DEFAULT todo ) ) with open(math_modeling_questions.json, encodingutf-8) as f: records json.load(f) for r in records: cur.execute( INSERT INTO questions (id, title, question, answer, status) VALUES (?, ?, ?, ?, todo), (r[id], r[title], \n.join(r[question]), \n.join(r[answer])), ) conn.commit() print(导入题数:, len(records))先执行 DROP TABLE 再建表保证重复执行脚本不会把同一套题重复导进去。question和answer都用换行拼接成长文本方便后面做全文检索。状态字段默认值是todo实际使用时可以自己改成doing或done用来做复习进度管理。5.2 校验8页资料的题号覆盖与答案完整度导入数据库之后第一件事不是立即查题而是校验。数学建模资料很多是从别人那里转发来的可能存在题号中断、答案缺失的问题。用一条SQL就能看清整体情况。SELECT COUNT(*) AS total, SUM(CASE WHEN TRIM(answer) THEN 0 ELSE 1 END) AS has_answer FROM questions;total是提取出的总题数has_answer是有答案内容的题数。如果has_answer明显少于total说明第3章的answer_anchor没有匹配到这部分答案的写法需要回头检查原始docx里答案区域的实际标题。这个校验在批量整理多个学期的数学建模资料时特别有参考价值能够快速暴露每份文档的抽取质量问题。5.3 检索时先做Unicode归一化数学建模题干里大量使用全角括号、全角数字比如“问题”和“问题1”看起来一样但在SQLite里是两个不同的字符串。直接用LIKE查询结果往往是搜不到。解决方法是入库文本和查询关键词都先过一次Unicode归一化。import unicodedata def normalize_text(s: str) - str: return unicodedata.normalize(NFKC, s).lower()NFKC会把全角数字、全角字母统一转成半角lower()处理英文关键词的大小写差异。实际查询时关键词和数据库里的字段都过这个函数匹配率会明显提升。keyword normalize_text(微分方程) cur.execute( SELECT id, title FROM questions WHERE question LIKE ? OR answer LIKE ?, (f%{keyword}%, f%{keyword}%), ) for row in cur.fetchall(): print(row)最后一个实用技巧数学建模答案里的图片、图表不会进入JSON抽取过程中如果发现答案段落里引用了“图1”或“表2”建议把原docx的word/media目录整体保留下来文件名按顺序导出到题库附件目录。这样后续复习时公式和图表不会丢数据建模类题目尤其依赖这种完整性。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门