
简介中华成语数据库是一份面向汉语学习者、语文教师、文化研究者及数据开发者的综合语料资源收录31851个成语每个成语均含拼音与释义多数还附有出处和例句可用于成语检索、教学备课、语言统计与文化溯源等场景。压缩包共3个文件约6.63MB以csv、sql、txt三种格式分别存储csv便于表格软件直接浏览与筛选sql可直接导入关系数据库进行建表与查询txt则适合纯文本阅读或二次处理满足不同技术背景用户的使用习惯。目前已有1066人学习下载说明其在成语数据整理领域具有一定参考价值。借助这份数据读者可以快速搭建本地成语词库按出处、关键字或拼音进行检索与频次统计也能结合出处与例句深入理解成语背后的历史典故为学术研究、课堂教学或个人兴趣提供扎实的数据支撑。1. 从一份 31851 条的中华成语数据库说起拼音、释义、出处、例句到底怎么用很多人第一次拿到「中华成语数据库总共31851个成语含拼音解释出处例子」这类资源时第一反应是解压、打开、扫一眼然后就没有然后了。真正卡住人的不是数据本身而是拿到一个 zip 之后怎么把它变成能查、能搜、能接进自己项目里的结构化数据。31851 条成语每条带拼音、解释大多数还有出处和例子这个体量放在本地跑全文检索、做成语接龙、做语文学习类小程序、做 NLP 语料预处理都够用。它适合三类人想快速搭一个成语查询服务的后端想做中文文本特征工程的数据同学以及需要离线词库的教育类产品开发者。这一章先把这份数据能解决什么问题讲清楚后面几章再拆解压、编码、入库、查询的完整链路。这份数据的价值不在「大」而在「字段齐」。拼音字段能直接支撑首字母检索和模糊匹配解释字段适合做全文索引出处和例子字段则是很多同类词库缺失的部分。你如果做过中文分词或者成语纠错就会知道带出处的语料有多难找。31851 这个量级覆盖了常用成语和大量生僻成语做本地词库完全够不需要联网调用接口。接下来要做的是把它从 zip 里安全地取出来处理编码问题再落到一个能查询的数据库里。整个过程不复杂但每一步都有容易翻车的地方尤其是编码和字段缺失。2. 解压、编码与字段结构把 zip 变成可用的 csv2.1 先看清 zip 里到底装了什么拿到 zip 之后不要急着双击解压到桌面。先在工作目录下用命令行看一眼内部结构避免解压出一堆嵌套文件夹或者带密码的文件。Windows 上用tar -tf或者 7-Zip 的命令行版本Linux 和 macOS 直接用unzip -l。这一步的目的是确认里面是单个 csv、多个 txt还是分门别类的文件。很多成语数据库会按拼音首字母拆成多个文件比如A.csv、B.csv也可能是统一一个idiom.csv。看清结构再决定后续是合并还是分表。unzip -l 中华成语数据库.zip这条命令只列出压缩包内容不解压。输出里重点看三样文件数量、文件扩展名、是否有中文文件名乱码。如果文件名显示为乱码说明压缩时用的是 GBK 编码解压时需要指定编码参数否则解压出来的文件名在 Linux 下会变成问号。常见做法是加-O GBK参数但不同版本的 unzip 支持情况不一样稳妥的方式是用 Python 的zipfile模块手动处理文件名编码。2.2 用 Python 安全解压并统一编码直接解压最大的风险是中文乱码。成语数据里拼音是 ASCII但解释、出处、例子全是中文一旦编码判断错整列数据就废了。我一般会先用 Python 读一小段探测实际编码再决定怎么转。下面这段脚本做三件事列出 zip 内文件、逐个读取前几行探测编码、把内容统一转成 UTF-8 写出。import zipfile import chardet zip_path 中华成语数据库.zip with zipfile.ZipFile(zip_path, r) as z: for info in z.infolist(): # 处理中文文件名编码zip 内部可能用 GBK try: name info.filename.encode(cp437).decode(gbk) except Exception: name info.filename print(文件:, name, 大小:, info.file_size) if name.endswith(.csv) or name.endswith(.txt): with z.open(info) as f: raw f.read(4096) # 只读前 4KB 探测编码 enc chardet.detect(raw)[encoding] print(探测编码:, enc)这段代码的关键在info.filename.encode(cp437).decode(gbk)。zip 格式本身对文件名编码没有统一规定Windows 压缩工具常用 GBK而 Python 默认按 cp437 解码所以要先还原再转 GBK。chardet.detect只用于探测不要全量依赖它因为短文本探测准确率有限。探测出编码后正式读取时用io.TextIOWrapper指定编码逐行写出 UTF-8 文件。如果探测结果是GB2312或GBK统一按GB18030读它是超集不会丢字。2.3 字段结构确认与缺失值处理解压出 csv 后先看表头。常见字段是idiom、pinyin、explanation、source、example但不同来源命名不一样有的用中文表头「成语」「拼音」「解释」「出处」「例子」。用 pandas 读的时候要显式指定encodingutf-8并检查列名。import pandas as pd df pd.read_csv(idiom.csv, encodingutf-8) print(df.columns.tolist()) print(df.shape) print(df.isnull().sum())df.isnull().sum()这一步很重要。标题里说「大多数还包括出处和例子」意味着有一部分成语的出处和例子是空的。这不是数据错误是正常缺失。处理方式取决于你的用途如果做查询展示空字段直接显示「暂无」如果做全文检索空值要填成空字符串避免NaN导致索引报错。我一般会把source和example两列的NaN统一填成空字符串拼音列如果有缺失则用pypinyin补但这份数据拼音字段基本完整补拼音属于兜底操作。提示不要用 Excel 直接打开 csv 再另存为Excel 默认按本地编码处理很容易把 UTF-8 中文变成乱码而且会擅自改动长数字和日期格式。处理数据优先用命令行或 Python。3. 入库选型SQLite、MySQL 还是直接上全文索引3.1 三种落地方式的取舍数据清洗完下一步是决定放哪里。31851 条成语单条记录平均几百字节整个数据集撑死几十 MB这个体量对数据库选型几乎没有压力。常见做法有三种SQLite、MySQL、以及直接上 Elasticsearch 或 Meilisearch 这类全文检索引擎。选哪个取决于你的使用场景。SQLite 适合本地工具、桌面应用、单机脚本。零配置一个文件搞定Python 内置支持查询成语用LIKE或者 FTS5 全文索引都行。MySQL 适合已经有服务端环境、需要多用户并发访问的场景比如给小程序或网站做后端。全文检索引擎适合需要拼音模糊匹配、首字母搜索、相关度排序的场景但引入成本高31851 条数据用 FTS5 其实已经够快。我的建议是先落 SQLite把查询逻辑跑通确认字段和检索需求之后再决定要不要迁到 MySQL 或搜索引擎。下面以 SQLite 为主线因为它的可复现性最强读者照着敲就能跑通。3.2 建表与批量导入的完整脚本建表时字段类型不用太纠结SQLite 是动态类型但为了可读性还是标清楚。成语本身加唯一索引避免重复导入。拼音字段单独存一列方便做首字母检索。import sqlite3 import pandas as pd df pd.read_csv(idiom.csv, encodingutf-8) df df.fillna() # 缺失值统一填空字符串 conn sqlite3.connect(idiom.db) cur conn.cursor() cur.execute( CREATE TABLE IF NOT EXISTS idioms ( id INTEGER PRIMARY KEY AUTOINCREMENT, idiom TEXT NOT NULL UNIQUE, pinyin TEXT, explanation TEXT, source TEXT, example TEXT ) ) # 批量插入用 executemany 提升速度 rows df[[idiom, pinyin, explanation, source, example]].values.tolist() cur.executemany( INSERT OR IGNORE INTO idioms (idiom, pinyin, explanation, source, example) VALUES (?, ?, ?, ?, ?), rows ) conn.commit() print(导入条数:, cur.execute(SELECT COUNT(*) FROM idioms).fetchone()[0]) conn.close()INSERT OR IGNORE配合idiom列的唯一约束能自动跳过重复成语。31851 条数据用executemany批量插入几秒内完成。如果数据量再大一个数量级可以改用事务分批提交但当前体量不需要。导入完成后一定要COUNT(*)验证条数如果明显少于 31851说明有重复或者解析时丢行需要回头检查 csv 是否有跨行字段。3.3 用 FTS5 建全文索引支撑解释和例句检索如果只按成语本身查普通索引就够。但很多场景要搜解释里的关键词比如搜「形容女子美貌」找出所有相关成语这时候LIKE %关键词%会全表扫描31851 条虽然不快也慢不到哪去但体验不好。SQLite 的 FTS5 扩展能建全文索引支持中文需要配合分词简单做法是按字切分或者用unicode61分词器。cur.execute( CREATE VIRTUAL TABLE IF NOT EXISTS idioms_fts USING fts5( idiom, pinyin, explanation, source, example, contentidioms, content_rowidid ) ) # 把主表数据同步进 FTS 表 cur.execute( INSERT INTO idioms_fts (rowid, idiom, pinyin, explanation, source, example) SELECT id, idiom, pinyin, explanation, source, example FROM idioms ) conn.commit()contentidioms表示 FTS 表不单独存数据而是引用主表节省空间。查询时用MATCH语法比如SELECT * FROM idioms_fts WHERE idioms_fts MATCH 美貌。中文分词在 FTS5 里默认按空格和标点切中文整句会被当成一个词所以搜「美貌」可能匹配不到「形容女子美貌」。解决办法是用tokenizeunicode61配合预处理把解释文本按字加空格或者直接用LIKE加普通索引。31851 条数据下LIKE的响应时间通常在几十毫秒对大多数应用够用。FTS5 更适合数据量上百万的场景这里了解即可不必强上。注意FTS5 的中文支持是常见坑点很多人建完索引发现搜不到就是因为分词器没配对。如果不想折腾分词直接用LIKE查询解释字段配合成语列的前缀索引性能完全可接受。4. 查询接口与拼音检索把数据库接进你的项目4.1 按成语、拼音、首字母三种查询方式数据入库后最常用的查询有三种精确查某个成语、按拼音全拼查、按拼音首字母查。前两种直接WHERE条件就行第三种需要额外处理。首字母检索的实现方式是在导入时多存一列pinyin_initial用拼音首字母拼接比如「一心一意」的拼音是yi xin yi yi首字母就是yxyy。from pypinyin import lazy_pinyin, Style def get_initials(pinyin_str): # 从已有拼音字段提取首字母拼音字段格式通常是 yi xin yi yi parts pinyin_str.split() return .join([p[0] for p in parts if p]) # 给 DataFrame 增加首字母列 df[pinyin_initial] df[pinyin].apply(get_initials)如果拼音字段本身是带声调的比如yī xīn yī yìp[0]取出来还是带声调的字母需要先去掉声调。pypinyin的Style.FIRST_LETTER能直接输出首字母但前提是你有汉字原文。这里因为已经有拼音列直接取首字母更快。建完这一列后在表上加索引查询时WHERE pinyin_initial yxyy就能秒出结果。4.2 一个最小可用的查询函数把查询逻辑封装成函数方便接进 Flask、FastAPI 或者桌面应用。下面这个函数支持按成语精确查、按关键词模糊查、按首字母查返回字典列表。def search_idioms(keywordNone, initialNone, limit20): conn sqlite3.connect(idiom.db) conn.row_factory sqlite3.Row cur conn.cursor() if initial: cur.execute( SELECT * FROM idioms WHERE pinyin_initial ? LIMIT ?, (initial.lower(), limit) ) elif keyword: cur.execute( SELECT * FROM idioms WHERE idiom LIKE ? OR explanation LIKE ? LIMIT ?, (f%{keyword}%, f%{keyword}%, limit) ) else: cur.execute(SELECT * FROM idioms LIMIT ?, (limit,)) results [dict(row) for row in cur.fetchall()] conn.close() return resultsrow_factory sqlite3.Row让查询结果能按列名访问转成字典后直接可以 JSON 序列化。LIMIT参数防止一次返回过多数据。模糊查询用了两个LIKE分别匹配成语本身和解释字段覆盖大部分搜索场景。如果要做分页加OFFSET参数即可但要注意OFFSET越大越慢数据量大时改用游标分页。4.3 接进 Web 服务时的注意事项如果你要把这个查询接进 Flask 或 FastAPI有几个点容易翻车。第一SQLite 在多线程下默认不允许跨线程共享连接Flask 每个请求要新建连接或者用连接池。第二返回的 JSON 里中文默认会被转义成\uXXXX需要在响应里设置ensure_asciiFalse。第三拼音字段如果带声调前端展示时要注意字体支持部分字体显示带声调字母会错位。from flask import Flask, jsonify, request import json app Flask(__name__) app.route(/idiom) def idiom_api(): kw request.args.get(kw, ) data search_idioms(keywordkw) return app.response_class( json.dumps(data, ensure_asciiFalse), mimetypeapplication/json )ensure_asciiFalse是关键不加的话返回给前端的中文全是 Unicode 转义虽然功能正常但调试时很难看。另外 SQLite 数据库文件要放在服务进程有读写权限的目录部署到服务器时注意文件路径不要写死成开发机的绝对路径。5. 避坑与排查成语数据库落地时最容易翻车的 5 个地方5.1 解压后中文全是乱码现象解压出来的 csv 用 Excel 打开中文显示为「锟斤拷」或者问号。原因zip 内文件名或文件内容用了 GBK 编码而解压工具按 UTF-8 处理。解决不要用图形界面解压改用 Python 的zipfile模块读取时用chardet探测编码统一转成 UTF-8 再写出。如果文件名乱码用info.filename.encode(cp437).decode(gbk)还原。5.2 导入后条数对不上 31851现象SELECT COUNT(*)查出来只有三万多一点或者少几百条。原因csv 里有重复成语被UNIQUE约束跳过了或者某些行有跨行字段pandas 解析时错位。解决先df.drop_duplicates(subset[idiom])看下去重后剩多少如果去重后接近 31851说明原始数据本身有重复。如果差得多用pd.read_csv(..., quotingcsv.QUOTE_ALL)或者调整sep参数重新解析。5.3 拼音检索搜不到结果现象按首字母yxyy查「一心一意」查不到。原因拼音字段格式不统一有的用空格分隔有的用连字符有的带声调。解决导入前统一拼音格式去掉声调符号统一用空格分隔再提取首字母。用pypinyin的Style.NORMAL去声调Style.FIRST_LETTER取首字母不要手动切字符串。5.4 LIKE 查询解释字段特别慢现象搜解释里的关键词响应要好几秒。原因LIKE %关键词%无法走索引全表扫描。解决31851 条数据下全表扫描通常不超过 100ms如果超过检查是不是每次查询都新建了数据库连接。连接建立的开销远大于查询本身。把连接复用或者用连接池性能立刻上来。如果数据量继续增长再考虑 FTS5 或外部搜索引擎。5.5 出处和例子字段为空导致程序报错现象查询结果里source是None前端渲染时报错。原因csv 里的空值被 pandas 读成NaN入库后变成NULL。解决df.fillna()在导入前统一填空字符串查询函数里对None做兜底。不要依赖数据库的DEFAULT值因为INSERT时显式传了None默认值不会生效。提示这五条里编码和拼音格式问题占了大多数。处理中文数据编码永远是第一道坎先把编码统一成 UTF-8后面的事会顺很多。6. 进阶用法用这份成语数据做拼音纠错和接龙校验数据跑通之后可以拿它做点更有意思的事。一个典型场景是成语接龙校验用户输入一个成语程序判断它是否在库中并找出下一个可接的成语。接龙规则通常是下一个成语的首字拼音首字母和上一个成语的尾字拼音首字母相同。有了pinyin_initial列这个逻辑很好实现。def chain_next(idiom): conn sqlite3.connect(idiom.db) cur conn.cursor() cur.execute(SELECT pinyin FROM idioms WHERE idiom ?, (idiom,)) row cur.fetchone() if not row: return None last_char_pinyin row[0].split()[-1] next_initial last_char_pinyin[0] cur.execute( SELECT idiom, pinyin FROM idioms WHERE pinyin_initial LIKE ? LIMIT 10, (next_initial %,) ) return cur.fetchall()这段代码先查成语的拼音取最后一个字的拼音首字母再找所有以该首字母开头的成语。实际接龙还要求首字相同严格玩法是首字汉字相同宽松玩法是首字母相同。你可以根据产品需求调整匹配规则。LIMIT 10是防止返回过多候选前端可以随机选一个展示。另一个进阶用法是拼音纠错。用户输入「一鸣惊人」但打成了「一明惊人」直接查是查不到的。可以用拼音做模糊匹配把用户输入转成拼音在库里找拼音相同但汉字不同的成语返回候选列表。pypinyin能把任意汉字转拼音配合pinyin列的索引能实现「音近字错」的纠错。这个功能在教育类产品里很实用学生打错字也能找到目标成语。用法依赖字段实现难度适用场景精确查询idiom低词典类应用首字母检索pinyin_initial低输入法、快速搜索解释关键词搜索explanation中语义检索、学习工具接龙校验pinyin中游戏、互动教学拼音纠错pinyin高输入纠错、教育产品最后说个我自己的习惯拿到任何中文数据集第一件事永远是统一编码第二件事是确认主键唯一性第三件事是跑一遍COUNT和NULL统计。这三步做完后面无论入库还是接接口基本不会出大问题。这份成语数据库字段齐、体量适中适合拿来练手也适合直接用在生产环境的小型项目里。希望帮到你。本文还有配套的精品资源点击获取