
简介这份核专业英语词汇文档面向核物理、核工程、放射化学及相关能源与核安全方向的学生、科研人员和工程技术人员用于解决阅读英文文献、撰写技术报告与外文交流时专业术语不熟的问题。资源包共1个doc文件约60KB篇幅紧凑按主题分节编排涵盖核物理基本概念、放射性、核反应等模块便于按需检索和背诵。词条采用中英对照形式既有element、atom、nucleus、proton、neutron、electron、nucleon等基础术语也收录isotope、binding energy、mass defect、energy level等进阶表达还延伸到fission、fusion、decay、chain reaction、radiation、transuranium element等核反应与辐射概念并细分带正电、带负电、不带电、电中性、化学键、化合物、原子序数、质量数、轨道电子等描述性短语和形容词搭配。此外还涉及宇宙射线、电离、韧致辐射、光电效应、湮灭、宏观截面、散射与衍射等内容方便读者在核电站运行、放射性物质处理、核医学等实际场景中准确理解与运用专业词汇。目前已有60人学习下载。1. 核专业英语词汇.doc 不是词典而是一份待处理的半结构化数据核专业英语词汇.doc 这类文件几乎每个核工程、辐射防护方向的课题组里都躺着更新过好几版几百到几千条英文术语配中文译名格式从两列表格到纯文本混排都有。它的价值不在于能打开而在于能不能被程序检索、被翻译工具当词表调用、被用来卡住文档里的术语一致性。肉眼翻文档找一条“反应堆压力容器”的英文要滚屏十几秒做成带索引的词库就是毫秒级返回。适合三类人要啃英文核工程标准与文献的研究生、做核领域技术翻译与本地化的工程师、以及要给行业文档做术语校验的研发。路线是解析、结构化、检索、增值四步每一步都给能直接跑的命令和代码。2. 把 核专业英语词汇.doc 变成可解析文本的三条路径2.1 先分清 .doc 还是 .docx这一步决定后面用什么工具很多文件名带 .doc 的核专业英语词汇表实际有两种完全不同的内部结构。老格式是 OLE2 复合文档文件头固定为D0 CF 11 E0 A1 B1 1A E1python-docx 完全读不了新格式其实是 OOXML 压缩包文件头是PK只是被人手工改过后缀。先判断再动手能省掉一半的排查时间。# 看文件头Composite Document File V2 是老 .docZip / Word 2007 是 docx file ./raw/nuclear_glossary.doc # 更直接地看魔数只读前 8 字节批量跑几十个文件也不卡 xxd -l 8 ./raw/nuclear_glossary.docfile命令输出里出现 “Composite Document File V2 Document” 就按老格式处理出现 “Microsoft Word 2007” 或 “Zip archive data” 就按 docx 处理。xxd -l 8只截前 8 字节比完整读取快得多适合放在批量脚本的第一道筛选里。文件特征判断方式推荐解析路径OLE2 复合文档file报 Composite Document File V2LibreOffice 转 docx 后接 python-docxOOXML 压缩包文件头为 PKfile报 Word 2007直接 python-docx或 unzip 取 word/document.xml纯文本 / Markdown文件头是可读 ASCII直接按行读跳过转换环节扫描件 PDFpdffonts查不到内嵌字体需先做 OCR属于另一条链路2.2 用 LibreOffice 无头模式批量转换的最小命令LibreOffice 的 headless 模式是最省心的转换器对中文和表格的处理比多数 Python 转换库都完整。关键是要指定独立的用户配置目录否则和桌面上已经打开的 LibreOffice 抢锁会直接失败而且报错信息很难看懂。# --headless 不开界面-env:UserInstallation 指定独立 profile避免与已开实例冲突 soffice --headless \ -env:UserInstallationfile:///tmp/lo_profile \ --convert-to docx --outdir ./out ./raw/*.doc # 再导一份纯文本用来看排版规律、试跑正则比在 docx 上调试快得多 soffice --headless \ -env:UserInstallationfile:///tmp/lo_profile \ --convert-to txt:Text (encoded):UTF8 --outdir ./out ./raw/*.doc--convert-to txt:Text (encoded):UTF8里的过滤器名必须写全只写txt在部分版本上会输出本地编码中文直接变乱码。--outdir不会自动创建多级目录得先mkdir -p。转换是幂等的同名文件会被覆盖所以原始 .doc 一定要留一份只读备份。批量转换时如果某个文件卡住超过 60 秒通常是文件里嵌了损坏的 OLE 对象先把它单独剔出去再跑。2.3 python-docx 按文档流读段落与表格核专业英语词汇表最常见的是“左边英文、右边中文”的两列表但页眉页脚、分类小标题会夹杂其中。如果只遍历doc.paragraphs就会把整张表格漏掉只遍历doc.tables又会丢掉分类标题正确做法是按 body 的子元素顺序走。from docx import Document from docx.table import Table from docx.text.paragraph import Paragraph def iter_block_items(doc): 按文档流顺序产出 Paragraph 和 Table保证分类标题与表格的相对位置不错乱 body doc.element.body for child in body.iterchildren(): if child.tag.endswith(}p): yield Paragraph(child, doc) elif child.tag.endswith(}tbl): yield Table(child, doc) doc Document(./out/nuclear_glossary.docx) for block in iter_block_items(doc): if isinstance(block, Paragraph): text block.text.strip() if text: print(P, text) else: for r_idx, row in enumerate(block.rows): # 合并单元格会让同一段文字在多个 cell 里重复出现用底层 tc 去重 seen, cells set(), [] for cell in row.cells: if id(cell._tc) in seen: continue seen.add(id(cell._tc)) cells.append(cell.text.strip()) print(T, r_idx, cells)iter_block_items靠 XML 标签后缀判断类型比在doc.tables和doc.paragraphs上分别遍历更可靠因为 docx 里表格和段落本来就是同级元素。row.cells在遇到横向合并时会把同一个单元格对象重复返回用id(cell._tc)去重是最省事的判据否则一行会读出三四个重复的中文译名后面去重逻辑全被污染。输出直接打上P和T前缀灌进文件后用 grep 就能快速定位排版异常的行。2.4 跨页表格与合并单元格造成的行错位怎么修跨页表格在 docx 内部其实还是一张表不会断开真正麻烦的是“分类占一整行”的合并行。这类行第一列是中文分类名、第二列为空解析时容易被当成残缺词条塞进数据库。判断规则很简单一行里有效单元格数小于 3 且没有任何 ASCII 字母就按分类标题处理只更新当前 domain 变量不产出词条。表格首行常是“英文 / 中文 / 备注”这样的表头用if r_idx 0 and re.search(r[Ee]nglish|英文, cells[0])这类启发式跳过比写死行号可靠得多换一份表也不会崩。还有一个隐蔽问题Word 里的软换行ShiftEnter在 docx 里是一个独立的w:br元素cell.text会把它拼成没有分隔的连续字符串遇到中英混排时需要在解析前把\n换成两个空格让正则的\s{2,}锚点重新生效。3. 从纯文本到结构化词条核专业英语词汇的字段与正则抽取3.1 先给词条定表结构再写抽取代码字段定得好后面检索和校验都省事。核领域术语有三个特点缩写密集如 RPV、LOCA、BWR、一词多译pressurizer 有时译“稳压器”有时译“加压器”、同一缩写跨领域含义不同SG 既可能是 steam generator也可能是 safety guide。表结构要把这些情况提前留出位置。字段类型示例说明enTEXTreactor pressure vessel英文全称保留原始大小写用于展示en_normTEXTreactor pressure vessel小写、去多余空格后的归一化形式用于去重和匹配abbrTEXTRPV缩写无则留空zhTEXT反应堆压力容器中文译名domainTEXTreactor领域标签来自表格里的分类标题src_lineINTEGER1842原始行号发现错译时能回原文核对updated_atTEXT2024-05-11词条最后修改时间en_norm这一列是整张表的关键。英文严格比大小写和连字符会制造大量假重复把Control Rod、control rod、control-rod归一到control rod之后去重和模糊匹配的准确率会明显上一个台阶。src_line看着多余实际是排错时最常用的字段——发现某条译名可疑直接跳回原文那一行看上下文。3.2 用正则吃下三种常见排版拍平后的文本基本逃不出三种形态空格对齐的两列、制表符分隔、以及英文全称后紧跟括号缩写的写法。正则按“最具体优先”排序逐条试命中就停。import re # 注意顺序带缩写的模式最具体放最前面避免被通用模式抢先匹配 PATTERNS [ # A. 英文全称 (缩写) 中文 re.compile(r^(?Pen[A-Za-z][A-Za-z0-9 \-\.]*?)\s*\((?Pabbr[A-Za-z0-9/\-]{2,12})\) r\s*[,、]?\s*(?Pzh[\u4e00-\u9fff].*)$), # B. 英文 [两个以上空格或制表符] 中文 re.compile(r^(?Pen[A-Za-z][A-Za-z0-9 \-,\/()\.]*?)\s{2,}(?Pzh[\u4e00-\u9fff].*)$), # C. 中文在前、英文在后少量表格是反排的 re.compile(r^(?Pzh[\u4e00-\u9fff][^\n]*?)\s{2,}(?Pen[A-Za-z][A-Za-z0-9 \-,\/()\.]*)$), ] def parse_line(line: str): line line.replace(\u3000, ).strip() # 全角空格先归一 if not line or len(line) 4: return None for pat in PATTERNS: m pat.match(line) if m: g m.groupdict() return { en: (g.get(en) or ).strip(), abbr: (g.get(abbr) or ).strip() or None, zh: (g.get(zh) or ).strip(), } return None\s{2,}是最常用的分隔锚点因为 Word 里用空格对齐的表格导出后通常保留两个以上空格。\u3000全角空格必须显式替换否则从 Windows 版 Word 导出的文件里到处都是“看不见的分隔符”正则全部落空。模式 C 放最后因为它最宽松容易误吞正常的两列数据。实际跑的时候建议把未命中的行单独写到unmatched.log人工扫一遍就知道自己的文件还有哪种排版没覆盖。3.3 缩写归并与一词多译的处理抽完之后别急着入库先做两件事。第一件是缩写归并把PWR (pressurized water reactor)拆成两条记录一条enpressurized water reactor, abbrPWR另一条enPWR, abbrPWR这样用户输缩写和输全称都能命中同一条中文。第二件是一词多译同一en_norm对应多个zh时不要覆盖用(en_norm, zh)做联合唯一索引全部保留检索时把多个译名一起返回让使用者自己选。-- 联合唯一索引允许一词多译但不允许完全重复的词条 CREATE UNIQUE INDEX IF NOT EXISTS ux_term_en_zh ON term(en_norm, zh);这样处理之后insert or ignore的语义就变得很干净完全相同的词条被丢弃同词不同译被保留同译不同词一个中文对应多个英文也会被保留下来正好留给第 5 章的一致性校验去发现。3.4 建库与批量插入SQLite 单文件、零依赖几千到几十万条术语完全够用扔进 Git 仓库里还能跟着版本走。CREATE TABLE IF NOT EXISTS term ( id INTEGER PRIMARY KEY, en TEXT NOT NULL, en_norm TEXT NOT NULL, abbr TEXT, zh TEXT NOT NULL, domain TEXT, src_line INTEGER, updated_at TEXT DEFAULT (datetime(now)) ); CREATE INDEX IF NOT EXISTS ix_term_en_norm ON term(en_norm); CREATE INDEX IF NOT EXISTS ix_term_abbr ON term(abbr);import sqlite3 def save(conn, rows): # INSERT OR IGNORE 配合唯一索引重复词条自动跳过不用先查一遍 conn.executemany( INSERT OR IGNORE INTO term(en, en_norm, abbr, zh, domain, src_line) VALUES (:en, :en_norm, :abbr, :zh, :domain, :src_line), rows ) conn.commit()INSERT OR IGNORE比REPLACE更适合这里REPLACE会删掉旧行再插新行id会变一旦有其他表按id引用就会连带出问题IGNORE保留首次出现的记录重复导入同一个 .doc 是安全的。en_norm的计算放在 Python 侧做用 .join(en.lower().split())三行就能写完比在 SQL 里嵌套lower()和replace()更好维护。4. 让 核专业英语词汇 可检索FTS5 索引与模糊匹配参数4.1 选分词器英文用 unicode61中文用 trigramFTS5 是 SQLite 自带的全文本索引不用装任何扩展。分词器选错是最常见的翻车点unicode61按空白和标点切词英文术语天然合适但它会把一整段中文当成一个 token“压力容器”就搜不到“反应堆压力容器”。中文侧改用trigram按三字符滑窗建索引任意子串都能命中。-- 英文侧unicode61 按词切分remove_diacritics 处理 é、ö 这类变音符号 CREATE VIRTUAL TABLE IF NOT EXISTS term_en_fts USING fts5( en, abbr, contentterm, content_rowidid, tokenizeunicode61 remove_diacritics 2 ); -- 中文侧trigram 支持任意子串匹配代价是索引体积约为原文的 3 到 4 倍 CREATE VIRTUAL TABLE IF NOT EXISTS term_zh_fts USING fts5( zh, contentterm, content_rowidid, tokenizetrigram );contentterm是 external content 模式FTS 表只存索引不存原文省掉一半存储代价是必须自己维护同步关系。remove_diacritics 2让Bézier和Bezier能互相命中核物理文献里作者名带变音符号的情况并不少见。-- 用触发器保证 term 表和两个 FTS 索引始终一致手写同步代码迟早会漏 CREATE TRIGGER IF NOT EXISTS term_ai AFTER INSERT ON term BEGIN INSERT INTO term_en_fts(rowid, en, abbr) VALUES (new.id, new.en, new.abbr); INSERT INTO term_zh_fts(rowid, zh) VALUES (new.id, new.zh); END;触发器一次插两份索引new.id对应content_rowidid。批量导入时如果为了速度临时删掉了触发器事后用INSERT INTO term_en_fts(term_en_fts) VALUES(rebuild)重建即可两个 FTS 表各跑一次。4.2 查询写法前缀、短语、缩写三件套术语检索的实际用法就三种记得开头几个字母、记得完整短语、只记得缩写。-- 前缀匹配press* 命中 pressurizer、pressure vessel、pressure tube SELECT t.en, t.abbr, t.zh FROM term_en_fts f JOIN term t ON t.id f.rowid WHERE term_en_fts MATCH en : press* ORDER BY rank LIMIT 20; -- 短语匹配精确找连续词组双引号在 FTS5 里表示 phrase SELECT t.en, t.zh FROM term_en_fts f JOIN term t ON t.id f.rowid WHERE term_en_fts MATCH en : control rod LIMIT 10; -- 缩写直查走普通索引比 FTS 更快因为缩写基本是等值查询 SELECT en, zh FROM term WHERE abbr LOCA;en : press*里的en :是列过滤语法只在en这一列上匹配能避免中文列里的内容干扰排序。ORDER BY rank用的是 FTS5 内建的 BM25 排序不加这一句返回顺序就是物理顺序看起来像是随机的。缩写查询走 B-Tree 索引而不是 FTS是因为LOCA这种查询几乎总要求精确匹配用不上相关性排序走索引延迟更低。-- 中文侧trigram 要求查询串至少 3 个字符“压力容器”没问题 SELECT t.en, t.zh FROM term_zh_fts f JOIN term t ON t.id f.rowid WHERE term_zh_fts MATCH 压力容器 LIMIT 10; -- 两字词堆芯、慢化达不到 trigram 最小长度退回 LIKE 兜底 SELECT en, zh FROM term WHERE zh LIKE %堆芯% LIMIT 10;注意trigram 分词器对少于 3 个字符的查询会直接返回空集不是报错。中文术语里两字词占比不低必须在应用层写一条“查询长度小于 3 时走 LIKE”的分支否则用户会以为词库里没有这个词。4.3 拼写容错rapidfuzz 的阈值怎么定英文术语拼错是常态FTS 的前缀匹配救不了pressuriser和pressurizer这种拼写差异得靠编辑距离。用 rapidfuzz 的token_set_ratio它对词序和多余词不敏感。from rapidfuzz import process, fuzz def fuzzy_lookup(query, vocab, cutoff85, limit5): vocab 是 [(en_norm, zh, en), ...] 的列表返回若干候选供人工确认 keys [v[0] for v in vocab] hits process.extract(query.lower(), keys, scorerfuzz.token_set_ratio, score_cutoffcutoff, limitlimit) return [(vocab[keys.index(k)][2], vocab[keys.index(k)][1], s) for k, s, _ in hits]阈值行为适用场景95 以上只召回几乎相同的写法自动纠错、批量替换85 到 95召回大小写、连字符、单复数差异交互式查询的默认值75 到 85开始出现字面相近但语义无关的术语只在用户点“没找到”后触发低于 75噪音过大候选里一半是错的不建议放进生产流程token_set_ratio比ratio更适合术语因为它先把两边拆成词集合再比交集pressure vessel和vessel pressure都能得到高分。score_cutoff设 85 是实践中比较稳的位置低于 80 会把moderator和radiator这类看着像但毫无关系的词也召回。vocab列表建议在进程启动时一次性加载进内存几千条术语的内存占用可以忽略避免每次查询都回表。4.4 用抽检集验证检索质量索引建完别急着交货。从原文里随机抽 100 条词条人为制造三类查询完整英文、前缀、中文译名各跑一遍算命中率。import sqlite3 conn sqlite3.connect(nuclear_glossary.db) sample conn.execute(SELECT en, zh FROM term ORDER BY RANDOM() LIMIT 100).fetchall() miss [] for en, zh in sample: # 前缀查询截前 6 个字符模拟“只记得开头”的真实场景 n conn.execute( SELECT COUNT(*) FROM term_en_fts f JOIN term t ON t.idf.rowid WHERE term_en_fts MATCH ?, (fen : {en[:6].lower()}*,) ).fetchone()[0] if n 0: miss.append((en, zh)) print(f前缀召回失败 {len(miss)}/100) for m in miss[:10]: print(m)失败样本基本集中在三类含特殊符号的术语U-235、n/γ、拉丁学名式的长复合词、以及原文排版错乱导致根本没抽进来的词条。前两类调整分词器的tokenchars参数把连字符和斜杠声明为词内字符就能解决第三类只能回原文修排版这正是src_line字段存在的意义。5. 核专业英语词汇的进阶用法术语一致性校验与增量更新词库建好之后最能体现价值的地方是拿它去扫英文技术文档把术语不一致找出来。核行业文档动辄要求“同一概念全文用词统一”人工校对根本盯不住。做法是把词库里的英文术语按长度降序排列对文档做最长优先匹配统计同一个中文概念下出现了哪些不同英文写法。import re, collections def check_consistency(text, terms): terms 为 [(en, zh)]返回 zh - {en: 出现次数} 的分布 mapping collections.defaultdict(collections.Counter) # 长度降序保证先匹配 reactor coolant pump 再匹配 pump for en, zh in sorted(terms, keylambda x: -len(x[0])): pattern re.compile(r\b re.escape(en) r\b, re.IGNORECASE) cnt len(pattern.findall(text)) if cnt: mapping[zh][en] cnt return {zh: dict(c) for zh, c in mapping.items() if len(c) 1}sorted(..., keylambda x: -len(x[0]))这行是关键不按长度降序pump会先把reactor coolant pump吞掉统计结果全是碎片。\b词边界防止rod命中erode。返回结果里同一个中文对应两个以上英文就是需要人工裁决的不一致点。增量更新同样重要。词汇表每隔几个月就会有人补充新词正确流程是先INSERT OR IGNORE入库、再和上次的快照比对只把真正的新增导出回 .doc而不是整表覆盖。用en_norm做 diff 的键能过滤掉大小写和连字符带来的假新增导出的补丁通常只有十几行评审起来毫无压力。校验项触发条件处理建议同一中文多个英文一个 zh 对应 2 个以上 en人工选定主译名其余标为别名同一英文多个中文一个 en_norm 对应 2 个以上 zh保留按领域拆分展示缩写冲突同一 abbr 指向不同全称按 domain 字段区分展示时带上领域拼写近似token_set_ratio 落在 85 到 95 之间列入待确认清单不自动合并最后一个小技巧把导出的 CSV 存成 UTF-8 带 BOMExcel 双击打开不乱码同时按en_norm排序人工翻阅时重复词条会自然挨在一起比任何自动去重脚本都更容易发现问题。本文还有配套的精品资源点击获取