
简介这是一份面向中文自然语言处理开发者、前端工程师及汉字数据研究者的汉语词典数据库资源以JavaScript与JSON为主要载体可用于汉字检索、拼音转换、字形分析等场景帮助解决中文文本处理中字词基础数据缺失的问题。压缩包共33个文件包含28个JSON数据文件、3个JavaScript脚本及说明文档整体约33.36MB。核心数据覆盖21104个汉字与符号含标点及数学符号完整数据细分为词语、带声调与无声调拼音、笔画数、偏旁、来源页面及详情文本等字段并提供分片文件便于版本比对另有精简版与纯汉字版满足不同体积需求。资源还附带拼音对照表与拆分脚本方便按需裁剪与二次加工。目前已有510人学习下载适合需要快速获取结构化汉字数据、搭建词典查询或进行文本分析的技术人员参考使用。1. 汉语词典数据库一个能塞进前端项目的离线词库做中文文本处理时分词、拼音标注、简繁转换、生僻字校验这几件事几乎每个项目都会撞上。在线 API 调用一次两次还行量一大就开始卡脖子延迟、限流、断网直接歇菜。我最近拆的这份chinese-dictionary资源本质就是一个把汉语词典数据打包成 JavaScript 可直接消费的离线词库覆盖汉字、词语、拼音、释义等字段适合塞进 Node 脚本、浏览器端工具、输入法辅助、教育类小应用里做本地查询。它不依赖任何后端服务不需要发 HTTP 请求拿到数据文件就能跑。如果你正在找一个能离线跑、字段结构清晰、能直接require或import的中文词典数据源这份东西值得花半小时摸一遍。2. 数据结构拆解汉字、词语、拼音三张表怎么组织2.1 先搞清楚数据文件长什么样拿到资源后第一件事不是急着写代码而是把数据文件打开看一眼。这类词典数据库通常按「汉字表」和「词语表」分开存储汉字表以单个字符为主键词语表以词条为主键。常见做法是用 JSON 或 JS 模块导出字段大致包括字段名含义示例char / word汉字或词条本身汉、汉语pinyin拼音带声调或不带hàn、hàn yǔradical部首氵strokes笔画数5explanation释义文本天河、银河traditional繁体写法漢实际字段名以你拿到的文件为准不同版本可能有增减。我一般会先跑一段脚本把顶层结构打印出来确认是数组还是对象、主键是什么、有没有嵌套。// inspect.js —— 先看数据结构别急着写业务 const data require(./chinese-dictionary/data/characters.json); // 打印顶层类型和前三条记录 console.log(顶层类型:, Array.isArray(data) ? Array : typeof data); console.log(记录总数:, Array.isArray(data) ? data.length : Object.keys(data).length); console.log(首条记录:, JSON.stringify( Array.isArray(data) ? data[0] : data[Object.keys(data)[0]], null, 2 ));这段脚本的作用是「探路」。Array.isArray判断是数组还是对象因为有些词典用{ 汉: {...} }这种以字为键的对象结构查询时直接data[汉]就行比数组遍历快得多。JSON.stringify带缩进打印能看清嵌套层级。跑完这一步你才知道后面该用find还是直接取键。2.2 拼音检索的两种实现路径词典数据里拼音字段的存储方式直接决定检索方案。常见有两种一种是带声调符号的hàn一种是不带声调的han加数字han4。前者可读性好后者方便做模糊匹配。如果你要做「输入拼音查汉字」的功能核心思路是把拼音字段预处理成统一格式再建索引。我一般会在加载阶段做一次归一化// pinyin-index.js —— 构建拼音到汉字的倒排索引 const characters require(./chinese-dictionary/data/characters.json); // 归一化去掉声调符号统一小写 function normalizePinyin(py) { return py .normalize(NFD) // 分解声调符号 .replace(/[\u0300-\u036f]/g, ) // 去掉组合用变音符号 .toLowerCase() .replace(/\s/g, ); // 去掉空格 } // 构建索引{ han: [汉, 汗, 罕], ... } const pinyinIndex {}; for (const item of characters) { const key normalizePinyin(item.pinyin); if (!pinyinIndex[key]) pinyinIndex[key] []; pinyinIndex[key].push(item.char); } // 查询示例 function searchByPinyin(input) { const key normalizePinyin(input); return pinyinIndex[key] || []; } console.log(searchByPinyin(han)); // 输出所有读 han 的汉字normalize(NFD)把带声调的字符拆成基础字母加组合符号再用正则去掉\u0300-\u036f范围内的变音符号这样hàn就变成了han。索引结构用对象做哈希表查询复杂度 O(1)。注意replace(/\s/g, )是处理多字词拼音之间可能有空格的情况比如hàn yǔ归一化后变成hanyu。提示如果你的数据里拼音是han4这种数字声调格式归一化时要把数字也去掉正则改成/[\u0300-\u036f0-9]/g。2.3 简繁转换的映射表怎么用简繁转换看着简单实际坑不少。一简对多繁的情况比如「发」对应「發」和「髮」如果只做字符级映射结果一定翻车。这份词典数据里如果带了traditional字段那它提供的是一对一映射适合做「展示用」的转换不适合做「语义级」的转换。我一般会这样处理先建简到繁的映射表转换时逐字查表查不到就保留原字。对于一简对多繁的情况如果数据里只给了一个对应关系那就在文档里标注清楚这个限制别让用户以为能完美转换。// simp-trad.js —— 基于词典数据的简繁映射 const characters require(./chinese-dictionary/data/characters.json); // 构建简到繁映射 const simpToTrad {}; for (const item of characters) { if (item.traditional item.traditional ! item.char) { simpToTrad[item.char] item.traditional; } } function toTraditional(text) { return text.split().map(ch simpToTrad[ch] || ch).join(); } console.log(toTraditional(汉语词典)); // 漢語詞典 console.log(toTraditional(头发)); // 頭發注意不是「頭髮」最后那个例子就是典型的坑「头发」的「发」在繁体里应该是「髮」但如果词典数据只存了「發」这个映射转换结果就是错的。所以用这份数据做简繁转换时心里要清楚它的边界——它适合做字形展示不适合做语义消歧。3. 从零跑通一个本地查询服务Node 脚本加 HTTP 接口3.1 用 Node 原生 http 模块起一个查询接口数据摸清楚了接下来把它变成一个能用的服务。虽然标题里带「http」但这份资源本身是数据不是服务。我一般会写一个轻量的 Node 脚本用原生http模块暴露几个查询接口方便其他程序调用。// server.js —— 基于原生 http 模块的词典查询服务 const http require(http); const url require(url); const characters require(./chinese-dictionary/data/characters.json); const words require(./chinese-dictionary/data/words.json); // 预处理建汉字哈希表 const charMap {}; for (const item of characters) { charMap[item.char] item; } // 预处理建词语哈希表 const wordMap {}; for (const item of words) { wordMap[item.word] item; } const server http.createServer((req, res) { const parsed url.parse(req.url, true); const pathname parsed.pathname; const query parsed.query; res.setHeader(Content-Type, application/json; charsetutf-8); if (pathname /char query.q) { const result charMap[query.q] || null; res.end(JSON.stringify({ code: 0, data: result })); } else if (pathname /word query.q) { const result wordMap[query.q] || null; res.end(JSON.stringify({ code: 0, data: result })); } else if (pathname /search query.q) { // 模糊搜索词条包含关键词 const keyword query.q; const results words .filter(w w.word.includes(keyword)) .slice(0, 20); res.end(JSON.stringify({ code: 0, data: results })); } else { res.statusCode 404; res.end(JSON.stringify({ code: 404, msg: not found })); } }); server.listen(3000, () { console.log(词典服务已启动: http://127.0.0.1:3000); });这段代码的关键点有三个。第一启动时就把数组转成哈希表查询时 O(1) 命中别每次请求都遍历数组。第二url.parse的第二个参数true会把 query string 解析成对象省得自己切字符串。第三/search接口做了slice(0, 20)限制返回条数防止关键词太泛导致响应体过大。启动后直接访问http://127.0.0.1:3000/char?q汉就能拿到「汉」字的完整数据。如果你要在这个基础上做前端页面记得处理跨域——原生 http 模块不会自动加 CORS 头需要手动res.setHeader(Access-Control-Allow-Origin, *)。3.2 连接复用与 keep-alive 的取舍热词里出现了「http连接复用」这在词典服务场景下确实值得聊一句。Node 的 http 模块默认对每个请求新建 TCP 连接如果你的查询服务要被高频调用比如输入法每敲一个字就查一次频繁建连的开销会累积。开启 keep-alive 的方式很简单在响应头里加Connection: keep-alive同时设置server.keepAliveTimeout// 在 createServer 回调里加上 res.setHeader(Connection, keep-alive); // 在 server.listen 之前设置超时 server.keepAliveTimeout 5000; // 5 秒内复用同一连接 server.headersTimeout 6000; // 要比 keepAliveTimeout 大keepAliveTimeout控制连接空闲多久后关闭headersTimeout必须比它大否则会出现连接还没复用就被掐断的情况。不过对于本地查询这种场景如果 QPS 不高开不开 keep-alive 差别不大别为了优化而优化。3.3 用 curl 和浏览器验证接口服务跑起来后验证步骤不能省。我一般用 curl 先过一遍# 查单个汉字 curl http://127.0.0.1:3000/char?q汉 # 查词语 curl http://127.0.0.1:3000/word?q汉语 # 模糊搜索 curl http://127.0.0.1:3000/search?q词典如果返回null先确认查询的字或词在数据里是否存在别急着怀疑代码。中文 URL 参数在 curl 里可能需要编码汉的 UTF-8 编码是%E6%B1%89不过现代终端一般能自动处理。浏览器里直接访问同样可行JSON 格式化插件会自动渲染。4. 避坑与排查词典数据落地时最容易翻车的五个点4.1 现象require JSON 报错「Unexpected token」原因数据文件不是标准 JSON可能是 JS 模块带module.exports或者 JSONP 格式。有些词典数据为了兼容浏览器直接加载会写成window.dictData {...}。解决先看文件头几行。如果是module.exports 开头用require没问题如果是window.xxx 需要改成module.exports或者用fs.readFileSync加正则提取。我一般会写个转换脚本统一成标准 JSON。4.2 现象拼音查询查不到但数据里明明有原因拼音字段的声调格式和你归一化逻辑不匹配。比如数据里是hàn带声调符号你按han4去匹配自然对不上。解决先打印几条原始拼音字段看格式再决定归一化策略。带声调符号的用normalize(NFD)去符号带数字的直接去数字。两种格式混存的情况也有归一化函数要同时处理。4.3 现象内存占用飙升Node 进程被 OOM kill原因词典数据全量加载到内存如果词语表有几十万条每条又有大段释义文本内存很容易上 G。解决按需加载。汉字表通常几千到一万条全量加载没问题词语表如果太大可以拆成多个分片文件查询时用require动态加载对应分片。或者改用 SQLite 存储用better-sqlite3做查询内存占用可控。4.4 现象HTTP 接口返回乱码原因响应头里Content-Type没指定charsetutf-8浏览器按默认编码解析。解决res.setHeader(Content-Type, application/json; charsetutf-8)这行不能省。另外JSON.stringify默认输出 UTF-8不用额外处理。4.5 现象模糊搜索返回结果太多前端卡死原因/search接口没做条数限制用户输入「一」这种高频字返回几万条。解决加slice(0, N)限制同时考虑加个offset参数做分页。如果要做真正的全文检索这份数据不适合得上 Elasticsearch 或 SQLite FTS。5. 进阶技巧把词典数据做成前端可用的离线包5.1 用 IndexedDB 做浏览器端持久化如果你要做纯前端的中文工具每次刷新都重新加载几 MB 的 JSON 不现实。常见做法是把数据写进 IndexedDB首次加载后缓存后续直接从本地数据库读。// idb-store.js —— 把词典数据写入 IndexedDB const DB_NAME chinese-dict; const STORE_NAME characters; function openDB() { return new Promise((resolve, reject) { const req indexedDB.open(DB_NAME, 1); req.onupgradeneeded (e) { const db e.target.result; if (!db.objectStoreNames.contains(STORE_NAME)) { db.createObjectStore(STORE_NAME, { keyPath: char }); } }; req.onsuccess () resolve(req.result); req.onerror () reject(req.error); }); } async function bulkInsert(items) { const db await openDB(); const tx db.transaction(STORE_NAME, readwrite); const store tx.objectStore(STORE_NAME); for (const item of items) { store.put(item); } return new Promise((resolve) { tx.oncomplete resolve; }); } async function queryChar(char) { const db await openDB(); const tx db.transaction(STORE_NAME, readonly); const store tx.objectStore(STORE_NAME); return new Promise((resolve) { const req store.get(char); req.onsuccess () resolve(req.result); }); }keyPath: char指定主键put方法在键存在时更新、不存在时插入。批量写入放在一个事务里比逐条写快一个数量级。查询时store.get直接按主键取速度极快。5.2 数据裁剪只保留你需要的字段原始词典数据字段往往很全但你的项目可能只需要char、pinyin、explanation三个字段。全量加载浪费带宽和内存我一般会写个裁剪脚本// trim.js —— 裁剪字段减小数据体积 const fs require(fs); const characters require(./chinese-dictionary/data/characters.json); const trimmed characters.map(item ({ char: item.char, pinyin: item.pinyin, explanation: item.explanation })); fs.writeFileSync( ./chinese-dictionary/data/characters.trim.json, JSON.stringify(trimmed), utf-8 ); console.log(裁剪完成: ${characters.length} 条 - ${(JSON.stringify(trimmed).length / 1024).toFixed(1)} KB);跑完看输出体积如果从几 MB 降到几百 KB前端加载体验会好很多。注意JSON.stringify不带缩进生产环境别用格式化输出能省不少空间。5.3 验证数据完整性的一个习惯从那以后我每次拿到这类词典数据都会先跑一遍完整性检查统计总条数、检查主键是否有重复、检查必填字段是否有空值。这个习惯帮我提前发现过好几次数据文件损坏的问题。// validate.js —— 数据完整性检查 const characters require(./chinese-dictionary/data/characters.json); const seen new Set(); let dupCount 0; let missingPinyin 0; for (const item of characters) { if (seen.has(item.char)) dupCount; seen.add(item.char); if (!item.pinyin) missingPinyin; } console.log(总条数: ${characters.length}); console.log(重复主键: ${dupCount}); console.log(缺失拼音: ${missingPinyin});如果重复主键大于 0说明数据合并时出了问题查询结果会不稳定。缺失拼音的条目在做拼音检索时会被漏掉心里要有数。这套检查脚本我一般会放在项目scripts/目录下每次更新数据后跑一遍比出了 bug 再回头查省事得多。希望帮到你。本文还有配套的精品资源点击获取