python-docx + SQLite FTS5 构建机械中英术语检索库 📅 发布时间:2026/9/17 17:07:15 👁 浏览次数: 简介面向机械类专业学生、新入职技术员及工程翻译人员的术语速查文档围绕中英对照的专业词汇展开解决课堂学习与现场工作中术语看不懂、译不准的问题。文档按笔画顺序编排覆盖螺丝批、二极管、力矩、力偶、力图、工程图、电路断路器、工件、工字梁、中央处理器、非铁金属、中密度纤维板、中碳钢等高频词条每条都给出中文释义与英文写法可快速定位并理解概念。整包仅含1个docx文件约46KB轻量便携可直接在Word中检索关键词也方便打印成随身词卡。内容从力学基础、材料分类延伸到机械制图、电工电子与建筑结构适合课前预习、课程复习也可在实操时随手查阅。目前已有127人学习下载是一份兼顾入门与查阅的实用工具。1. 一份按笔画排的机械中英词表为什么值得当成数据资产拆一遍如果你做过制造业的翻译、图纸本地化或者售后知识库大概率被扔过这么一份 .docx标题写着《机械类专业词汇表》打开以后没有表格、没有字段、没有分隔符就是一行接一行的「中文术语 English term」靠「一画」「二画」「三画」这类笔画标题隔开。字面上它是给人翻的实际用起来更像一份没有 schema 的字典。真正折腾人的地方在于它同时是三种东西一份中英对照词表、一份索引笔画就是排序键、一份被污染过的中间产物。「工作面」写成「事情面」「工具钢」写成「东西钢」「中央处理器」写成「中央处置惩罚器」。不是错别字那种偶尔出现而是全文系统性替换直接扔进 CAT 工具或者检索引擎第一次查询就会翻车。把这种 docx 拆干净其实是一个很典型的小型数据处理任务解析、归一化、落库、加检索。下面按这个顺序走一遍代码可以直接抄词表也可以换成你手里的那一份。2. python-docx 解析从「二画」段落里抠出中英术语对2.1 先看清结构一行一条笔画标题是隐式分区docx 本质是个 zip解开之后的word/document.xml里全是w:p段落。这份词表一个术语占一行笔画标题也单独成段。所以解析逻辑就是一个段落流加一个状态机不需要动 XML 层级。这类文件常见的几种「脏」法中英文之间混用全角空格与半角空格、中文术语里夹半角括号注释比如「令(纸张的计数单位) ream」、开头用*当占位符「*形顶尖 fork centre」。所以切分点不能写死成单个空格得按「第一个空白符」切并且要求英文侧全部落在 ASCII 可打印区间。字段含义示例stroke笔画分区二画zh中文术语未拆同义项弓形手钻手摇曲柄钻en英文术语bracenote中文侧括号注释纸张的计数单位2.2 段落流解析代码import re from docx import Document STROKE_HEAD re.compile(r^[一二三四五六七八九十]画$) # 中文在前、英文在后中文以非 ASCII 开头英文全落在 ASCII 可打印区间 SPLIT re.compile(r^([^\x00-\x7f].*?)[\s\u3000]([\x20-\x7e].*)$) def iter_terms(path): 逐段产出 (笔画分区, 中文, 英文)不是术语行的直接跳过并打印 doc Document(path) stroke None for p in doc.paragraphs: line p.text.strip() if not line: continue if STROKE_HEAD.match(line): stroke line continue m SPLIT.match(line) if not m: print(SKIP:, line) # 脏行留痕别静默丢弃 continue yield stroke, m.group(1).strip(), m.group(2).strip()三个关键点。[^\x00-\x7f]要求首字符是非 ASCII这样反着写的行英文在前会被直接挡掉。.*?用非贪婪碰到第一个空白就停比贪婪匹配稳因为中文侧本身可能带括号和分号。[\s\u3000]把全角空格显式列出来Python 在 Unicode 模式下\s其实能匹配\u3000但写出来更抗以后换实现。2.3 三种典型失败行原始行问题处理办法令(纸张的计数单位) ream中文侧含半角括号保留正文括号内容另存一列*形顶尖 fork centre星号当占位符切分前先替换*→ 叉十字榫 cross halving joint全角空格分隔切分前做空白归一化星号那行最阴。*属于 ASCII正则一跑就会把英文侧起点定到*上中文和英文同时错位但脚本不报错。所以修复动作必须放在切分之前而不是解析之后。2.4 加一层校验挡住「像术语但不是」的行def is_valid(zh: str, en: str) - bool: if len(zh) 1 or len(en) 2: return False if not re.search(r[A-Za-z]{2,}, en): # 英文侧至少两个连续字母 return False if re.search(r^[A-Za-z], zh): # 中文侧不该以字母开头 return False return True校验规则不追求百分百准确目的是让页码残留、目录行、空表头这类边界数据在导入阶段就冒出来。被丢弃的行数要单独统计宁可人工再过一遍也不要让脏行进索引。3. 术语清洗与归一化分号多义项、缩略语和同形替换污染3.1 分号是同一术语的同义项不是一句话「弓形手钻手摇曲柄钻 brace」这种写法说明一个英文词对应两个中文说法全角分号和半角分号都出现过。正确做法是拆成多行写入用同一个术语组 id 关联而不是把分号揉进一列靠 LIKE 去撞。揉进去的后果是搜索「手摇」时命中不到因为整串被当成一个不可分的中文词。3.2 缩略语的三种抽取情形括号后置是主流写法但括号里的东西是不是缩略语不能靠长度判断——(a.c.)这种带点的也得收。抽取策略是先取括号尾再用大写字母做主判断小写带点的走白名单。原始英文抽出的缩写命中规则medium density fibre board (MDF)MDF括号尾 全大写alternating current (a.c.)a.c.括号尾 白名单acrylonitrile-butadiene-styrene (ABS)ABS括号尾 全大写顺带一个副产品全称里的拼写错误可以靠缩写校验反查出来。比如缩写是 ABS而全称写成stryrene而不是styrene字母序列对不上就该起告警。3.3 同形替换污染必须建映射表「工作」被系统性写成「事情」、「工具」变成「东西」、「处理」变成「处置惩罚」这类错误一次覆盖全文逐条人工改不现实。写一张修复表长词排前面避免短规则先把长词切碎。import re # 按长度倒序保证「处置惩罚」先于任何 2 字规则匹配 FIX_MAP sorted([ (处置惩罚, 处理), (事情, 工作), (东西, 工具), (本领, 能力), (宁静, 安全), ], keylambda kv: -len(kv[0])) MULTI_SEP re.compile(r[;]) def normalize_zh(raw: str) - list[str]: s raw.replace(\u3000, ).strip().replace(*, 叉) for bad, good in FIX_MAP: s s.replace(bad, good) # 「弓形手钻手摇曲柄钻」→ [弓形手钻, 手摇曲柄钻] return [x.strip() for x in MULTI_SEP.split(s) if x.strip()]映射表的顺序是这段代码里唯一需要动脑的地方。映射项少的时候看起来无所谓一旦扩到几十条短词先替换就会吃掉长词的匹配窗口出现「处置惩罚器」被改成「处理惩罚器」这类二次污染。3.4 去重与冲突一词多译该保留还是合并按 (zh, en) 去重不会出问题真正麻烦的是同一中文对应多个英文比如「内螺纹制造法」和「攻丝」都指向 tapping。从字面判断不了是同一工序还是两道不同工序我的做法是全部保留加一列conflict打标导出后人工复核。冲突类型判定依据处理方式同中文多英文zh 相同、en 不同打标输出待审同英文多中文en 相同、zh 不同合并为同义项组仅大小写差异casefold 后相同取出现次数多者4. 落库与检索jieba 分词 SQLite FTS5 做中英双向术语查询4.1 表结构设计-- 主表一条术语一行 CREATE TABLE term ( id INTEGER PRIMARY KEY, zh TEXT NOT NULL, -- 中文术语如「弓形手钻」 en TEXT NOT NULL, -- 英文术语如 brace abbr TEXT, -- 缩略语如 MDF stroke TEXT -- 笔画分区如「二画」 ); -- 全文索引中文列写 jieba 分词结果英文列写小写原文 CREATE VIRTUAL TABLE term_fts USING fts5( zh_seg, en_norm, abbr, contentterm, content_rowidid, tokenizeunicode61 remove_diacritics 2 );FTS5 自带的 unicode61 对中文是按字切的「弓形手钻」会被拆成四个单字搜「手钻」根本命中不了。解决办法是在写入阶段就用 jieba 切好、空格拼回把结果存进zh_seg列索引只吃这一列。import jieba import sqlite3 conn sqlite3.connect(terms.db) cur conn.cursor() def seg(text: str) - str: # cut_for_search 会额外切出细粒度词「弓形手钻」也能召回「手钻」 return .join(jieba.cut_for_search(text)) for zh, en, abbr, stroke in rows: cur.execute(INSERT INTO term(zh, en, abbr, stroke) VALUES (?,?,?,?), (zh, en, abbr, stroke)) rid cur.lastrowid cur.execute( INSERT INTO term_fts(rowid, zh_seg, en_norm, abbr) VALUES (?,?,?,?), (rid, seg(zh), en.lower(), (abbr or ).lower()) ) conn.commit()英文侧只做 lower不做词干还原。术语里大量是复合名词和缩写stemming 会把tapping和tap混成一类机械语境下这两个词指的东西不一样。4.2 三类查询意图的 MATCH 写法查询意图MATCH 表达式说明中文词反查英文zh_seg:扳手输入先过 jieba 再拼串英文词正查中文en_norm:brace*前缀匹配兜住复数与变形缩写反查全称abbr:MDF缩写单独建列避免被空格切碎-- 中文 → 英文 SELECT t.zh, t.en FROM term_fts f JOIN term t ON t.id f.rowid WHERE term_fts MATCH zh_seg:弓形 手钻 ORDER BY rank LIMIT 10; -- 英文 → 中文前缀匹配 SELECT t.zh, t.en FROM term_fts f JOIN term t ON t.id f.rowid WHERE term_fts MATCH en_norm:brace* ORDER BY rank LIMIT 10;最容易踩的坑在 Python 侧拼串用户输入是「弓形手钻」四个字连着必须自己先切一遍再拼进 MATCH否则 FTS5 拿整串去匹配一无所获。切完还要留在同一对双引号里双引号在 FTS5 里表示短语匹配拆成两个引号就变成 OR 语义了。4.3 为什么不上 Elasticsearch几千条术语SQLite 单文件加 FTS5 绰绰有余部署就是拷一个 .db 文件。除非要把术语库和在线的图纸库、手册全文混在一起做统一召回否则为这点数据起一个 ES 集群不划算。真要迁把zh_seg换成ik_max_word分析器查询侧结构基本不动。5. 增量维护与质检让术语库在半年后还能对上5.1 三条能自动跑的质检规则缩写必须能从全称首字母拼出来。medium density fibre board取首字母是 MDB而实际缩写是 MDF一眼就知道全称或缩写至少有一处写错了。中文侧不允许出现半角英文字母出现基本是切分错位。同一zh下en数量超过 3大概率是污染造成的重复行而不是真有三种译法。def check_abbr(full: str, abbr: str) - bool: if not abbr: return True # 只取每个单词首字母忽略连字符与括号 words [w for w in full.replace(-, ).split() if w[:1].isalpha()] return .join(w[0] for w in words).upper() abbr.upper()alternating current→a.c.这种带点的写法会让函数判假所以这条规则只能输出警告不能直接删数据交给人判定。5.2 增量导入写成幂等词表会更新重跑导入脚本不能插出两份。给 (zh, en) 建唯一索引配合 upsertCREATE UNIQUE INDEX IF NOT EXISTS ux_term_zh_en ON term(zh, en); INSERT INTO term(zh, en, stroke) VALUES (?, ?, ?) ON CONFLICT(zh, en) DO UPDATE SET stroke excluded.stroke;外部内容模式的 FTS5 表在 UPDATE 时不会自动同步要么挂触发器要么在脚本末尾显式执行INSERT INTO term_fts(term_fts) VALUES(rebuild)。几千条规模重建一次是毫秒级直接重建比维护触发器省心也不会漏掉分支。5.3 用词表反查历史文案的译法一致性产品手册和 UI 文案里如果已经用了别的译法术语库再准也落不了地。可以拿术语库当白名单去扫一遍历史文档把英文术语在原文里定位出来再看同段落的中文是否落在术语库给出的候选集内落在集合外的行单独输出成待审清单。这一步不需要模型正则加段落对齐就能跑能挡住大部分「同一颗螺丝在三个页面里叫三个名字」的情况。还有一个导出前的收尾动作*占位符和中文侧括号注释必须在写 TBX 或 CSV 之前处理掉否则下游 CAT 工具会把占位符当成术语本体的一部分写进译文里再也洗不干净。本文还有配套的精品资源点击获取