算機(jī)訓(xùn)練題.doc:格式轉(zhuǎn)換與題庫(kù)提取實(shí)戰(zhàn)指南)
簡(jiǎn)介在日常辦公與備考場(chǎng)景中我們經(jīng)常會(huì)收到來自網(wǎng)絡(luò)的.doc文檔這類舊版Word格式可能攜帶宏病毒因此安全打開是第一步。理解Office受保護(hù)視圖的原理合理設(shè)置信任中心并用PowerShell或oletools進(jìn)行預(yù)檢能有效規(guī)避風(fēng)險(xiǎn)。將.doc轉(zhuǎn)換為.docx則是后續(xù)利用python-docx等工具提取文本的基礎(chǔ)LibreOffice頭模式提供了高效批量轉(zhuǎn)換方案。針對(duì)覆蓋計(jì)算機(jī)二級(jí)C語言、計(jì)算機(jī)組成原理等考點(diǎn)的訓(xùn)練題文檔借助正則表達(dá)式可將題目結(jié)構(gòu)化進(jìn)而構(gòu)建自測(cè)題庫(kù)。文章以一份實(shí)際訓(xùn)練題文件為例演示從安全驗(yàn)證、格式轉(zhuǎn)換到題庫(kù)拆解的完整流程幫助備考者高效刷題、查漏補(bǔ)缺。1. “計(jì)算機(jī)訓(xùn)練題.doc”到底是什么一份能直接刷的題庫(kù)還是一個(gè)要拆的怪盒如果你在考研群、畢設(shè)小組或同事U盤里拿到一份名為“[詳細(xì)完整版]計(jì)算機(jī)訓(xùn)練題.doc”的文件第一反應(yīng)多半是雙擊打開。可Windows常常會(huì)彈出“你嘗試預(yù)覽的文件可能對(duì)你的計(jì)算機(jī)有害。如果你信任此文件以及其來源請(qǐng)打開此文”很多人被這句警告勸退順手就把文件刪了。這份文檔的真實(shí)身份大概率是一份覆蓋計(jì)算機(jī)基礎(chǔ)、計(jì)算機(jī)組成原理、計(jì)算機(jī)二級(jí)C語言常考點(diǎn)的訓(xùn)練題集只是它被塞進(jìn)了老舊的.doc容器里正文里還帶著公式、圖片甚至早期文檔才有的宏。這篇文章不聊虛的就講我拿到這類文件后怎么安全打開、怎么把題目結(jié)構(gòu)化、哪些坑會(huì)讓人白折騰一晚上。適合備考計(jì)算機(jī)二級(jí)、復(fù)習(xí)計(jì)算機(jī)組成原理和計(jì)算機(jī)系統(tǒng)結(jié)構(gòu)的讀者照著走一遍。2. 打開.doc前的安全課為什么Windows會(huì)警告“對(duì)計(jì)算機(jī)有害”以及怎么正確解除2.1 先搞懂警告來源宏、外部鏈接和“保護(hù)視圖”當(dāng)Windows彈出一句“你嘗試預(yù)覽的文件可能對(duì)你的計(jì)算機(jī)有害”時(shí)很多人第一反應(yīng)是殺毒軟件報(bào)毒了其實(shí)這是Office的受保護(hù)視圖提醒。受保護(hù)視圖的邏輯是對(duì)來自Internet、郵件附件或受限目錄的文檔先在一個(gè)隔離環(huán)境里渲染預(yù)覽默認(rèn)禁止編輯、禁止宏、禁止ActiveX控件。這么做的目的就是為了防止一份看似正常的doc在你雙擊的瞬間執(zhí)行惡意代碼。所以“預(yù)覽可能有害”這句話的準(zhǔn)確含義是在沒確認(rèn)內(nèi)容之前最穩(wěn)妥的辦法是只看不編輯。為什么這類警告總跟.doc綁在一起因?yàn)?doc是OLE2復(fù)合文檔格式它可以嵌入宏、嵌入對(duì)象、嵌入DDE域和外部鏈接。歷史上以宏病毒形式傳播的惡意Word文檔絕大多數(shù)都采用.doc后綴。Kill宏病毒的原理是檢測(cè)VBA工程里是否有AutoOpen、DocumentOpen這類自動(dòng)宏。如果某個(gè)訓(xùn)練題doc里有自動(dòng)宏你雙擊打開的一瞬間宏代碼就可能運(yùn)行。所以看到一個(gè)舊版訓(xùn)練題doc第一件事不是看題而是看它有沒有宏。還要注意一個(gè)細(xì)節(jié)文件資源管理器在顯示“來自Internet”時(shí)實(shí)際上給文件關(guān)聯(lián)了一條NTFS數(shù)據(jù)流Zone.Identifier。Office讀到ZoneId為3Internet時(shí)就啟用受保護(hù)視圖。你可以把文件從下載目錄拖到桌面這條標(biāo)記仍然存在因?yàn)闃?biāo)記跟隨文件本身而不是目錄。所以“我從下載文件夾拷出來了它應(yīng)該安全”這種想法靠不住。在Windows里我一般這樣判斷文件大小小于10KB但文件名寫著“詳細(xì)完整版”可疑文件屬性里沒有作者、沒有修訂信息只有“來自Internet”可疑雙擊后打開進(jìn)入受保護(hù)視圖說明確有標(biāo)記不是殺毒誤報(bào)殺毒軟件掃描無異常只能說明沒有已知病毒不能說明沒有宏。真正拿到訓(xùn)練題doc別急著雙擊。先做掃描再看宏再?zèng)Q定要不要“啟用編輯”。這套習(xí)慣能擋掉絕大多數(shù)麻煩。2.2 用Word/WPS的安全打開三連解除鎖定、信任中心與只讀啟動(dòng)在確認(rèn)文件來源基本可信后再用辦公軟件打開。這里的操作順序我總結(jié)成“先解除鎖定再設(shè)宏安全最后只讀啟動(dòng)”。解除鎖定在文件上右鍵“屬性”常規(guī)頁(yè)簽底部有一個(gè)“解除鎖定”復(fù)選框前面有個(gè)安全鎖圖標(biāo)。勾上它Windows會(huì)刪除文件上的Zone.Identifier標(biāo)記。這樣再雙擊Office就不會(huì)強(qiáng)行用受保護(hù)視圖打開這個(gè)文件。注意只有文件確實(shí)來自Internet時(shí)這個(gè)復(fù)選框才會(huì)出現(xiàn)。如果文件是通過FTP、本地U盤拷貝過來的可能沒有這個(gè)選項(xiàng)那就跳過不影響后面。宏設(shè)置打開Word后進(jìn)入“文件 選項(xiàng) 信任中心 信任中心設(shè)置 宏設(shè)置”選擇“禁用所有宏并發(fā)出通知”。這個(gè)選項(xiàng)的意思是文檔里的宏不會(huì)自動(dòng)執(zhí)行但如果文檔確實(shí)包含宏Word會(huì)彈一個(gè)通知條提醒我。相比之下“禁用所有宏而不通知”過于安靜反而讓我不知道這文件里帶沒帶宏“啟用所有宏”則完全是給惡意文檔開門不要選。WPS里對(duì)應(yīng)位置通常在“設(shè)置 安全設(shè)置 宏安全性”同樣選禁用。只讀啟動(dòng)在Word里用“文件 打開”選中文件后不直接雙擊而是點(diǎn)擊打開按鈕旁邊的下拉箭頭選“以只讀方式打開”。如果擔(dān)心宏寫入文件這個(gè)操作能保證當(dāng)前會(huì)話只讀。訓(xùn)練題嘛本來就只需要看不需要改原文件。只讀打開后如果看到“啟用編輯”按鈕點(diǎn)它不會(huì)讓宏自動(dòng)運(yùn)行只要你不點(diǎn)“啟用內(nèi)容”。宏設(shè)置是“禁用并通知”所以此時(shí)“啟用內(nèi)容”才是放行的開關(guān)。還有一點(diǎn)值得說如果只是臨時(shí)看題不需要把訓(xùn)練題doc轉(zhuǎn)成docx直接看就行。一旦想修改或者做題庫(kù)就另存為docx。另存的過程會(huì)把舊的OLE對(duì)象重新封裝一遍文檔里的VBA宏如果是不受歡迎的Word通常會(huì)在保存時(shí)提示或清除相關(guān)宏。這等于給文件做了一次“凈化”。2.3 不靠Office也能驗(yàn)貨用PowerShell和oletools取樣很多情況下我不想打開Word再判斷尤其是來路不明的“[詳細(xì)完整版]計(jì)算機(jī)訓(xùn)練題.doc”。命令行比圖形界面更適合批量排查我先看文件有沒有Internet標(biāo)記再算哈希然后掃宏。# 查看文件是否帶著來自網(wǎng)絡(luò)的Zone.Identifier標(biāo)記 Get-Item -Path C:\Users\test\Downloads\[詳細(xì)完整版]計(jì)算機(jī)訓(xùn)練題.doc -Stream Zone.Identifier -ErrorAction SilentlyContinue | Format-List # 計(jì)算SHA256留底之后方便跟發(fā)布者核對(duì)文件是否一致 Get-FileHash -Path C:\Users\test\Downloads\[詳細(xì)完整版]計(jì)算機(jī)訓(xùn)練題.doc -Algorithm SHA256 | Format-List第一條命令如果輸出ZoneId3說明文件確實(shí)來自Internet如果沒有任何輸出可能是本機(jī)生成的也可能是所在磁盤不支持NTFS流。第二條命令生成一個(gè)64位哈希值這個(gè)值相當(dāng)于文件指紋。拿到指紋后發(fā)給傳文件給你的人他在自己電腦上算一遍SHA256如果兩個(gè)哈希一致說明文件在傳輸過程中沒有被替換也沒有發(fā)生損壞。這個(gè)操作在排查“文檔打開報(bào)錯(cuò)”時(shí)特別好用因?yàn)楹芏唷?doc打不開”其實(shí)根本不是Office問題是文件從網(wǎng)盤下載下來少了一半字節(jié)。看完哈希再掃宏。先安裝oletoolspip install oletools olevba -c C:\Users\test\Downloads\[詳細(xì)完整版]計(jì)算機(jī)訓(xùn)練題.doc-c參數(shù)讓olevba只打印檢測(cè)到的宏代碼。如果輸出區(qū)域顯示“VBA Macros: No”說明這個(gè)doc里沒有VBA工程可以放心用Word打開。如果顯示有AutoOpen、DocumentOpen這類自動(dòng)宏就要警惕最好先搞明白宏里面的代碼到底干什么。注意oletools還能檢測(cè)DDE、外部關(guān)系但命令行里最常用的是olevba和oleid。一個(gè)訓(xùn)練題doc如果同時(shí)滿足“來自Internet 沒有宏 哈希正?!被究梢源_定只是普通文檔。提示把doc拖進(jìn)在線掃描服務(wù)前先想清楚里面有沒有個(gè)人或敏感信息。訓(xùn)練題通常不涉及隱私但如果你不放心還是本地用oletools掃更穩(wěn)妥。3. 把.doc里的訓(xùn)練題變成可用的題庫(kù)文本提取與結(jié)構(gòu)化3.1 為什么不能直接用python-docx打開.doc先轉(zhuǎn)成.docx刷題刷多了就會(huì)發(fā)現(xiàn)手工翻Word文檔效率太低尤其這份“訓(xùn)練題doc”可能有幾百道題。很多人想寫腳本提取文本第一步就翻了車python-docx打開.doc文件直接拋PackageNotFoundError或docx file invalid。原因不是代碼寫錯(cuò)而是python-docx只支持Office Open XML格式也就是.docx。doc是OLE2復(fù)合文檔內(nèi)部結(jié)構(gòu)是一堆Stream和Storage跟docx的ZIP目錄結(jié)構(gòu)完全是兩碼事。Windows上最簡(jiǎn)單的方案是手動(dòng)用Word打開然后另存為docx但只能一個(gè)文件一個(gè)文件地轉(zhuǎn)。如果訓(xùn)練題有好幾個(gè)doc手工操作非常浪費(fèi)時(shí)間。我一般用LibreOffice的無頭模式批量轉(zhuǎn)換。LibreOffice是免費(fèi)開源辦公套件有命令行接口能跑在Windows、Linux和macOS上。mkdir -p converted libreoffice --headless --convert-to docx [詳細(xì)完整版]計(jì)算機(jī)訓(xùn)練題.doc --outdir converted--headless表示不啟動(dòng)圖形界面適合在服務(wù)器上跑--convert-to docx指定輸出格式--outdir converted把生成的docx放到converted目錄。如果遇到包含中文文件名的情況建議保持雙引號(hào)包裹否則部分Linux shell會(huì)因括號(hào)或空格解析錯(cuò)亂。Windows下如果提示libreoffice: command not found是因?yàn)榘惭b時(shí)沒有把LibreOffice寫進(jìn)PATH??梢杂萌窂綀?zhí)行 C:\Program Files\LibreOffice\program\soffice.exe --headless --convert-to docx C:\work\[詳細(xì)完整版]計(jì)算機(jī)訓(xùn)練題.doc --outdir C:\work\converted需要批量轉(zhuǎn)換時(shí)在Linux/macOS下用循環(huán)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是當(dāng)前文件的完整路徑避免工作目錄不同導(dǎo)致找不到源文件。轉(zhuǎn)換時(shí)間不長(zhǎng)幾兆的文件耗時(shí)幾秒鐘。轉(zhuǎn)換過程如果報(bào)錯(cuò)通常有三種LibreOffice沒有安裝、源文件被占用、輸出目錄不存在。先創(chuàng)建converted目錄再執(zhí)行命令。3.2 遇到“dify unstructured api url is not configured for doc file processing”時(shí)怎么繞開除了本地刷題還有人想把這套訓(xùn)練題喂給AI知識(shí)庫(kù)讓大模型根據(jù)這份doc出題或者答疑。常見做法是使用Dify這類平臺(tái)搭建一個(gè)知識(shí)庫(kù)上傳文檔后讓平臺(tái)自動(dòng)抽取文本。如果你直接把“.doc”拖上去平臺(tái)往往回你一句dify unstructured api url is not configured for doc file processing。這句話的意思是Dify處理doc文件依賴一個(gè)叫Unstructured的文檔解析服務(wù)而部署Dify時(shí)后臺(tái)沒有配置那個(gè)服務(wù)的API地址。于是系統(tǒng)無法對(duì)doc做文本抽取。這個(gè)報(bào)錯(cuò)跟你的訓(xùn)練題沒關(guān)系是平臺(tái)配置缺失。兩條出路第一條如果你能控制Dify服務(wù)的環(huán)境變量到后臺(tái)配置UNSTRUCTURED_API_URL讓它指向可用的Unstructured服務(wù)地址。第二條也是最省事的一條不要直接傳doc而是先按3.1節(jié)的方法在本地把doc轉(zhuǎn)成docx再上傳。Dify對(duì)docx的解析不需要調(diào)Unstructured因?yàn)樗陨砟茏x取docx內(nèi)部的文本節(jié)點(diǎn)。我在部署經(jīng)驗(yàn)里吃過這個(gè)虧后來凡是遇到doc文件都養(yǎng)成了先轉(zhuǎn)docx再喂平臺(tái)的習(xí)慣。這不僅能繞開Dify的配置問題也能減少其他知識(shí)庫(kù)工具的兼容性報(bào)錯(cuò)。如果堅(jiān)持要在本地起Unstructured服務(wù)可以用Docker起一個(gè)鏡像把宿主機(jī)端口映射成服務(wù)端口然后在Dify的配置里填http://localhost:8000。但這對(duì)于一份訓(xùn)練題來說明顯是殺雞用牛刀。本地轉(zhuǎn)格式是零依賴的兜底方案。3.3 用正則把題目拆成結(jié)構(gòu)化條目題號(hào)、題干、選項(xiàng)、答案轉(zhuǎn)成docx后真正的難點(diǎn)是把雜亂的題目拆成結(jié)構(gòu)化數(shù)據(jù)。我先把拆題過程拆成兩步第一步統(tǒng)計(jì)題號(hào)格式第二步按統(tǒng)計(jì)結(jié)果做正式拆分。先寫統(tǒng)計(jì)腳本from collections import Counter from docx import Document doc Document(converted/[詳細(xì)完整版]計(jì)算機(jī)訓(xùn)練題.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[選項(xiàng)] 1 print(patterns.most_common(10))這段代碼遍歷每個(gè)段落分別統(tǒng)計(jì)“1.”“第1題”和“A.”三類開頭的數(shù)量。輸出能告訴你這份訓(xùn)練題的主要排版風(fēng)格。如果“第X題”出現(xiàn)次數(shù)很多正式拆分時(shí)就要優(yōu)先用中文題號(hào)。如果“1.”很多就用數(shù)字題號(hào)。不要跳過這步因?yàn)閃ord訓(xùn)練題里經(jīng)常出現(xiàn)“第2題”和“2、”混用直接寫死正則會(huì)拆出大量垃圾條目。統(tǒng)計(jì)完以后執(zhí)行正式拆分import re from docx import Document ITEMS [] CUR None def flush(): if CUR is not None: ITEMS.append(CUR) doc Document(converted/[詳細(xì)完整版]計(jì)算機(jī)訓(xùn)練題.docx) for para in doc.paragraphs: text para.text.strip() if not text: continue # 數(shù)字題號(hào)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 # 中文題號(hào)第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 # 選項(xiàng)行 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 # 其他都算題干補(bǔ)充 CUR[body].append(text) flush() print(拆出題目數(shù):, len(ITEMS))這段代碼的關(guān)鍵是CUR字典它保存正在組裝的一道題。遇到新的題號(hào)時(shí)先把上一題存進(jìn)ITEMS再新建當(dāng)前題。選項(xiàng)行單獨(dú)匹配答案行同樣單獨(dú)匹配。正則里的(\d{1,3})限制題號(hào)最多三位目的是防止把“1.2 小節(jié)編號(hào)”誤判成題目編號(hào)。如果訓(xùn)練題是多選題答案可能是“ABC”或“ABCD”正則里的[A-D]{1,4}就是這個(gè)作用。單選的答案字符串只有1個(gè)字符拆出來也不影響。有些訓(xùn)練題答案不跟題而是集中在文檔末尾的“參考答案1-5 ABCDA6-10 BCDAB”這種段落。如果要處理這種集中式答案需要額外寫一段區(qū)間解析。我的做法是單獨(dú)讀取以“參考答案”開頭的段落用(\d)-(\d)\s*[:]?\s*([A-D])匹配題號(hào)區(qū)間和答案串然后把答案串按字符切開回填到對(duì)應(yīng)題目的answer字段。這是拆題時(shí)最容易被忽略的部分因?yàn)槿绻鸢感泻皖}目不在一起上面這段代碼拆出的所有答案都是None。另外python-docx的doc.paragraphs只包含段落不包含表格里的內(nèi)容。如果訓(xùn)練題的題干或選項(xiàng)放在Word表格里段落遍歷會(huì)漏掉。遇到這種情況我一般先用doc.tables把所有單元格文本抽出來再跟段落文本合并成一個(gè)“全文行列表”。合并后再跑拆分題目數(shù)量就對(duì)得上了。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)注意表格里的文本順序不一定是題目順序因?yàn)閃ord表格有合并單元格和行列結(jié)構(gòu)。如果源文檔把一題一個(gè)表格順序是對(duì)的如果所有題目塞進(jìn)一個(gè)大表格取出來順序容易亂。所以我在拆題前總會(huì)在統(tǒng)計(jì)腳本里加一行判斷l(xiāng)en(doc.tables)如果表格數(shù)量接近題目數(shù)說明是“題表格”結(jié)構(gòu)可以用表格方式拆如果只有一個(gè)表格那還是先復(fù)制到文本編輯器里轉(zhuǎn)成純文本再處理比較保險(xiǎn)。4. 圍繞計(jì)算機(jī)組成原理與計(jì)算機(jī)二級(jí)C語言這份訓(xùn)練題怎么學(xué)才不白刷4.1 先把題目按“計(jì)算機(jī)系統(tǒng)結(jié)構(gòu)/組成原理/操作系統(tǒng)/網(wǎng)絡(luò)”歸類訓(xùn)練題這種doc一般不會(huì)像教材那樣按章節(jié)涇渭分明地排。它前面可能是Windows常識(shí)后面突然跳到進(jìn)程調(diào)度再過兩頁(yè)又是C語言指針。從頭刷到尾最大的問題是你刷完100道題根本不知道自己哪塊弱。所以我拆完題以后第一件事是打標(biāo)簽。我給自己定的標(biāo)簽范圍是四類組成原理包含計(jì)算機(jī)系統(tǒng)結(jié)構(gòu)、操作系統(tǒng)、網(wǎng)絡(luò)、C語言。這四類基本覆蓋了計(jì)算機(jī)二級(jí)C語言和考研408的??挤较?。打標(biāo)簽可以用關(guān)鍵詞規(guī)則先初篩再人工確認(rèn)。下面是一個(gè)可用的Python示例import re TAG_RULES [ (r(補(bǔ)碼|原碼|反碼|浮點(diǎn)|IEEE|Cache|主存|流水線|中斷|DMA|尋址|字長(zhǎng)|ALU), 組成原理), (r(進(jìn)程|線程|死鎖|信號(hào)量|頁(yè)面置換|虛擬內(nèi)存|文件系統(tǒng)|磁盤調(diào)度), 操作系統(tǒng)), (r(TCP|UDP|IP地址|子網(wǎng)|交換機(jī)|路由器|OSI|幀|端口), 網(wǎng)絡(luò)), (r(指針|數(shù)組|結(jié)構(gòu)體|函數(shù)|遞歸|printf|scanf|sizeof), C語言), ] def classify(text): for pattern, label in TAG_RULES: if re.search(pattern, text): return label return 計(jì)算機(jī)基礎(chǔ)分類規(guī)則很簡(jiǎn)單但很實(shí)用。看到“Cache”“主存”“流水線”幾乎可以確定是組成原理題??吹健敖M間串行進(jìn)位”這是并行進(jìn)位鏈的考點(diǎn)屬于計(jì)算機(jī)系統(tǒng)結(jié)構(gòu)里比較經(jīng)典的內(nèi)容。這類題不能只看答案最好畫一畫進(jìn)位鏈的傳遞邏輯否則遇到換一種參數(shù)的題又會(huì)錯(cuò)。有的訓(xùn)練題還會(huì)包含“計(jì)算機(jī)系統(tǒng)結(jié)構(gòu)”和“計(jì)算機(jī)組成原理”的邊界題比如區(qū)分“透明性”“并行性”。我的處理原則是只要題目在說硬件內(nèi)部如何工作就歸到組成原理只要題目在說整機(jī)屬性或性能指標(biāo)就歸到計(jì)算機(jī)系統(tǒng)結(jié)構(gòu)。不用搞得很嚴(yán)格刷題只是為了查漏補(bǔ)缺。標(biāo)簽打完后我給每類題用不同策略復(fù)習(xí)。C語言題先用編譯器驗(yàn)證組成原理題動(dòng)筆算網(wǎng)絡(luò)和操作系統(tǒng)題重復(fù)記憶。如果一份訓(xùn)練題里“操作系統(tǒng)”類題目明顯多說明這份doc的出題偏向系統(tǒng)方向如果“組成原理”類多那更像是考研復(fù)習(xí)材料。根據(jù)自己的目標(biāo)調(diào)整刷題順序比死磕原文檔順序效率高。4.2 二級(jí)C語言題的“三遍刷法”讀題→畫內(nèi)存→對(duì)答案計(jì)算機(jī)二級(jí)C語言是這份訓(xùn)練題被廣泛搜索的核心關(guān)鍵詞。二級(jí)C語言考試?yán)镏羔?、?shù)組、結(jié)構(gòu)體、函數(shù)調(diào)用這些小題很多人看書感覺自己都會(huì)一到考試就發(fā)現(xiàn)輸出跟預(yù)想的不一樣。原因很簡(jiǎn)單C語言的內(nèi)存模型不是靠眼睛看會(huì)的。我處理二級(jí)C語言題的固定方法是“三遍刷法”。第一遍只看題不碰編譯器。遇到指針或數(shù)組的代碼片段在草稿紙上畫內(nèi)存。四個(gè)字節(jié)的格子變量名寫在上面指針用箭頭指向格子。寫出代碼執(zhí)行到每個(gè)語句后的狀態(tài)。第二遍打開編譯器把題干里的代碼原樣敲進(jìn)去運(yùn)行看實(shí)際輸出跟手推的差在哪。絕大多數(shù)情況下差別來自的優(yōu)先級(jí)、*p和(*p)的區(qū)別、數(shù)組下標(biāo)從0開始的次數(shù)錯(cuò)誤。第三遍把錯(cuò)的題號(hào)和關(guān)鍵字寫進(jìn)錯(cuò)題本。這個(gè)錯(cuò)題本不用寫整題只寫“*p等價(jià)于*(p)”這種一兩行結(jié)論。下面這個(gè)C語言片段幾乎能覆蓋所有指針自加考點(diǎn)#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; }第一次運(yùn)行前我先在紙上寫p指向a[0]*p先取a[0]的值1然后指針移動(dòng)到a[1]所以第一個(gè)printf輸出1第二個(gè)printf里*p變成2。實(shí)際運(yùn)行時(shí)如果輸出順序和你預(yù)想不一致就說明對(duì)“后置”的求值時(shí)機(jī)理解有偏差。二級(jí)C語言就喜歡考這類細(xì)節(jié)單獨(dú)背語法規(guī)則容易忘跑一遍編譯器印象會(huì)深很多。還要注意如果代碼片段里有scanf、gets這些輸入函數(shù)單獨(dú)跑時(shí)要有輸入數(shù)據(jù)。我的習(xí)慣是把輸入寫進(jìn)一個(gè)文本文件運(yùn)行命令改成./a.out input.txt這樣每道題都能可重復(fù)驗(yàn)證。4.3 唐朔飛課后題與訓(xùn)練題混用的邊界什么時(shí)候別迷信答案準(zhǔn)備計(jì)算機(jī)考研的同學(xué)手邊通常有唐朔飛《計(jì)算機(jī)組成原理》的課后題和這份訓(xùn)練題。這兩類題可以一起做但心里要有數(shù)訓(xùn)練題是“考點(diǎn)掃描”唐朔飛的教材題是“原理推導(dǎo)”。掃描題往往只給結(jié)論推導(dǎo)題需要你從頭寫過程。混著刷時(shí)最忌諱的是把訓(xùn)練題答案當(dāng)成絕對(duì)權(quán)威。舉個(gè)常見的沖突點(diǎn)Cache的寫直達(dá)法和寫回法。有的訓(xùn)練題直接問“Cache更新主存的方式有哪些”答案列了一個(gè)“寫直達(dá)”沒有提“寫回”。可唐朔飛的教材里這兩種方案都會(huì)詳細(xì)對(duì)比。如果你只是背了“寫直達(dá)”這個(gè)詞下次考試換個(gè)方式問“什么情況下寫回法優(yōu)于寫直達(dá)”照樣不會(huì)。所以我做這類題時(shí)只要訓(xùn)練題答案里出現(xiàn)“Cache”“主存”“寫直達(dá)”這些詞就會(huì)去翻教材把兩種策略的適用條件抄在題目旁邊。再比如“機(jī)器字長(zhǎng)”的定義不同教材的用語略有差異。唐朔飛強(qiáng)調(diào)機(jī)器字長(zhǎng)是CPU一次能處理的數(shù)據(jù)位數(shù)而某些訓(xùn)練題答案把存儲(chǔ)器的位寬也扯進(jìn)來結(jié)果兩道題答案對(duì)不上。這種情況我以教材為準(zhǔn)訓(xùn)練題答案標(biāo)注為“有爭(zhēng)議”。復(fù)習(xí)時(shí)不要浪費(fèi)時(shí)間去背一個(gè)錯(cuò)誤說法。如果備考的是軟件設(shè)計(jì)師或其他計(jì)算機(jī)職業(yè)資格考試訓(xùn)練題里的組成原理部分同樣可以作為基礎(chǔ)練習(xí)但軟考更偏體系結(jié)構(gòu)、指令流水線和存儲(chǔ)系統(tǒng)訓(xùn)練題里偏老的硬件常識(shí)題可以跳過。計(jì)算機(jī)程序設(shè)計(jì)員Java三級(jí)這類考試也會(huì)考計(jì)算機(jī)基礎(chǔ)知識(shí)和C語言語法這份doc里的二級(jí)C語言段落當(dāng)熱身正合適。題目來源覆蓋風(fēng)格答案可靠度建議用法訓(xùn)練題doc碎、雜、考點(diǎn)面廣中偶有印刷錯(cuò)誤先掃描知識(shí)盲區(qū)唐朔飛課后題推導(dǎo)鏈完整高有教材依據(jù)重點(diǎn)章節(jié)精做真題/模擬題貼近考試角度高考前限時(shí)刷5. 避坑指南訓(xùn)練題doc的5個(gè)常見坑每個(gè)坑都能讓你白折騰一晚上5.1 坑1公式和圖片抽不出來的最大元兇是OLE對(duì)象現(xiàn)象用python-docx讀取轉(zhuǎn)換后的docx題目文本能拿到但數(shù)學(xué)公式全部變成空白或者圖片位置只顯示一個(gè)空段落。碰到“浮點(diǎn)數(shù)加減法”這類題題干缺了核心表達(dá)式根本沒法判斷選項(xiàng)到底在問哪個(gè)兩個(gè)數(shù)相加。原因doc里的公式如果是由微軟公式編輯器或MathType插入的真正的內(nèi)容不在文本流里而在OLE對(duì)象里。python-docx主要讀取w:t文本節(jié)點(diǎn)OLE對(duì)象以二進(jìn)制形式嵌入在word目錄下不暴露給paragraph.text。圖片也一樣doc里如果嵌入了WMF/EMF矢量圖轉(zhuǎn)成docx后雖然還掛著但python-docx默認(rèn)不會(huì)把它轉(zhuǎn)成可讀文本。解決如果只是看題不追求文本抽取直接讓LibreOffice把doc轉(zhuǎn)成PDF公式和圖片會(huì)以矢量或位圖方式留在PDF里。命令很簡(jiǎn)單把--convert-to docx換成--convert-to pdf。如果一定要文本接受缺失把題干里的“______”當(dāng)占位符公式部分手動(dòng)補(bǔ)錄。想自動(dòng)提取公式目前只有把公式轉(zhuǎn)成圖片再用OCR識(shí)別成本高且對(duì)訓(xùn)練題來說不劃算。5.2 坑2題號(hào)正則匹配錯(cuò)亂因?yàn)椤暗?題”和“1、”混用現(xiàn)象拆分腳本跑完題目數(shù)量少了三分之一。打開JSON一看有的題干被塞進(jìn)上一題的body有的題號(hào)根本沒出現(xiàn)。原因這份doc很可能不是一個(gè)人排的版。前面幾章用“1、”后面幾章用“第22題”還有的題號(hào)后面是中文全角句號(hào)“”。統(tǒng)計(jì)腳本里只用^(\d{1,3})[\.、\)]匹配遇到“第11題”就匹配不上這段文字就會(huì)當(dāng)成普通文本追加到上一道題里。解決拆分前必須跑統(tǒng)計(jì)腳本并把它輸出的所有編號(hào)格式都納入正則匹配。正確的匹配順序是先匹配第(\d)題再匹配(\d{1,3})[\.、\)]。因?yàn)椤暗?1題”里的數(shù)字也可被第二個(gè)正則吃掉但如果先匹配中文格式就不會(huì)誤拆。同時(shí)統(tǒng)計(jì)腳本里的.要寫成\.否則“1a”這種也會(huì)被當(dāng)成題號(hào)。全角句點(diǎn)“”的Unicode是UFF0E正則里直接寫字面量編碼工具一般都能識(shí)別。5.3 坑3直接用python-docx打開.doc報(bào)錯(cuò)“docx file invalid”現(xiàn)象明明文件名是訓(xùn)練題.docDocument(訓(xùn)練題.doc)卻拋出PackageNotFoundError或者干脆報(bào)docx file invalid。原因python-docx的解析器完全依賴ZIP格式的docx結(jié)構(gòu)而doc是OLE復(fù)合文檔。它打不開doc不是代碼不兼容是格式根本不支持。很多新手在這里卡殼以為是文件壞了其實(shí)是選錯(cuò)了工具。解決先做格式轉(zhuǎn)換再用python-docx讀。Windows下如果堅(jiān)持用Word COM也不是不行$word New-Object -ComObject Word.Application $word.Visible $false $doc $word.Documents.Open(C:\temp\[詳細(xì)完整版]計(jì)算機(jī)訓(xùn)練題.doc) $doc.SaveAs2(C:\temp\計(jì)算機(jī)訓(xùn)練題.docx, 16) $doc.Close() $word.Quit()這里SaveAs2的第二個(gè)參數(shù)16是wdFormatXMLDocument也就是保存為docx。COM方案的問題是Word版本不同枚舉值可能變化而且服務(wù)器上COM權(quán)限經(jīng)常抽風(fēng)。LibreOffice的headless命令行更穩(wěn)定推薦優(yōu)先使用3.1節(jié)里的方案。記住任何需要批量處理的場(chǎng)景都不要走圖形界面另存為。5.4 坑4文件損壞或頁(yè)面異常一打開就轉(zhuǎn)圈甚至系統(tǒng)重啟現(xiàn)象雙擊doc后Word一直卡在“正在修復(fù)”界面幾分鐘后進(jìn)程無響應(yīng)個(gè)別老筆記本直接藍(lán)屏重啟。把文件拷到同事電腦上可能又能正常打開。原因文件在U盤拷貝或網(wǎng)盤下載過程中沒有完整寫入造成OLE2容器結(jié)構(gòu)損壞。還有一種可能是文檔里嵌入了損壞的OLE對(duì)象比如MathType公式的某個(gè)片段壞掉了Office渲染時(shí)觸發(fā)崩潰。跟宏病毒不一定有關(guān)系但體驗(yàn)上像“中招了”。解決先別雙擊。用2.3節(jié)的Get-FileHash算一下文件大小和哈希如果大小只有幾十KB基本可以判斷不完整。然后用LibreOffice嘗試轉(zhuǎn)換libreoffice --headless --convert-to txt [詳細(xì)完整版]計(jì)算機(jī)訓(xùn)練題.doc能轉(zhuǎn)出txt說明文檔主體還能讀如果LibreOffice也卡住就說明容器本身壞得厲害。遇到這種情況只能找原始來源重新獲取一份。我之前整理舊題庫(kù)時(shí)遇到過一個(gè)“打開就重啟”的doc后來發(fā)現(xiàn)是某道題里嵌入了一個(gè)損壞的Excel對(duì)象用LibreOffice轉(zhuǎn)PDF繞過去才把題目看全。5.5 坑5Word自動(dòng)編號(hào)導(dǎo)致復(fù)制粘貼后題目順序錯(cuò)亂現(xiàn)象從訓(xùn)練題里挑選20道組成原理題復(fù)制到新文檔后所有編號(hào)從“1、”重新開始。原來題干里的“第3題”字樣不見了做Excel統(tǒng)計(jì)時(shí)匹配不上原題號(hào)。原因Word里的“編號(hào)列表”不是實(shí)實(shí)在在的文本而是一個(gè)自動(dòng)編號(hào)域。復(fù)制粘貼到新文檔時(shí)如果目標(biāo)文檔的列表模板也定義了自動(dòng)編號(hào)新位置會(huì)按順序重新生成。這種引用關(guān)系并不保留原來的題號(hào)語義。解決復(fù)制之前先全選CtrlA然后復(fù)制到新文檔里右鍵選“粘貼為純文本”或“只粘貼文本”。這樣自動(dòng)編號(hào)會(huì)落成普通字符格式可能會(huì)亂但題號(hào)不再是“活”的。對(duì)于做題庫(kù)來說犧牲格式換取真實(shí)文本是劃算的。粘貼后跑一遍3.3節(jié)的統(tǒng)計(jì)腳本如果還能識(shí)別出“1.”和“第X題”的數(shù)量就說明題號(hào)已經(jīng)變成純文本了。別直接CtrlV否則你會(huì)在刷題后臺(tái)看到一堆“1、1、1、1”的假編號(hào)。6. 把訓(xùn)練題做成自測(cè)腳本用Python模擬考試環(huán)境并統(tǒng)計(jì)錯(cuò)題把題目拆進(jìn)JSON之后這份訓(xùn)練題才真正算自己的。我最常用的自測(cè)腳本不到一百行。題庫(kù)格式固定成這樣{ id: 1, tag: 組成原理, question: Cache寫回法與寫直達(dá)法的主要區(qū)別是, options: {A: 每次寫操作都更新主存, B: 只更新Cache, C: 寫操作只寫主存, D: 寫操作同時(shí)更新主存和Cache}, answer: B }然后用random.sample隨機(jī)抽20題答題后對(duì)錯(cuò)題累計(jì)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(錯(cuò)題ID:, [x[0] for x in wrong])腳本里的random.sample每次從題庫(kù)里取不同題目適合模擬考試。如果想反復(fù)刷錯(cuò)題就改成只從wrong列表里選或者給每道題加一個(gè)wrong_count字段權(quán)重越高抽中概率越大。我自己的做法是當(dāng)天用這20題模擬錯(cuò)題ID寫進(jìn)wrong_ids.txt第二天只從這些題里再抽10道直到正確率超過90%。這樣做能明顯減少盲目重復(fù)刷整卷的時(shí)間。最后一件事是我這些年整理訓(xùn)練題最深的教訓(xùn)別貪多先入庫(kù)再刷題。早期我拿到訓(xùn)練題doc第一時(shí)間就是從頭看結(jié)果看完就忘。后來改成先把題目結(jié)構(gòu)化再按知識(shí)點(diǎn)歸類最后用腳本自測(cè)一份幾百題的文檔只要一個(gè)晚上就能變成可復(fù)用的刷題系統(tǒng)。如果你也常跟舊版doc文件打交道建議把這個(gè)流程固定下來安全驗(yàn)貨、轉(zhuǎn)格式、拆題入庫(kù)、分類自測(cè)。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取