公司动态

dictionary项目main.jl源码逐行精讲:用状态机解析29MB纯文本生成8.6万条JSON定义

📅 2026/8/23 12:08:30
dictionary项目main.jl源码逐行精讲:用状态机解析29MB纯文本生成8.6万条JSON定义
dictionary项目main.jl源码逐行精讲用状态机解析29MB纯文本生成8.6万条JSON定义【免费下载链接】dictionaryA JSON representation of Websters Unabridged Dictionary项目地址: https://gitcode.com/gh_mirrors/dictio/dictionarydictionary是一个用 Julia 编写的轻量级词典解析项目它的main.jl脚本仅 82 行代码就能把 28MB 的《韦氏未缩编英语词典》纯文本Websters Unabridged Dictionary逐行扫描用三个状态变量组成的迷你状态机最终产出 8.6 万条 单词 → 定义 的dictionary.json数据以及一份描述词间语义关系的graph.json关系图。本文带你逐行读懂这套解析逻辑适合想学习如何把非结构化文本变成结构化 JSON的初学者。 项目全貌4 个数据文件 2 个源码文件在动手读代码前先认识这个项目的家当均位于仓库根目录文件大小作用dictionary.txt约 28MB原始词典纯文本共 97 万余行dictionary.json约 8.6MB解析产物86036 条单词→定义映射graph.json约 11MB图结构每个单词→定义中用到的其他单词main.jl82 行核心解析脚本本文的主角_.jl约 50 行自制的 underscore 风格小工具库README.md-项目说明与运行方式原始文本长这样dictionary.txt开头部分A A (named a in the English, and most commonly ä in other languages). Defn: The first letter of the English and of many other alphabets. The capital A of the alphabets of Middle and Western Europe, ... 2. (Mus.) Defn: The name of the sixth tone in the model major scale ...规律一目了然大写字母开头的行是词条头Defn:行是定义空行是定义的分隔符。main.jl的全部工作就是把这个规律翻译成代码。 第 1 步读入并清洗文本第 4~13 行先做最朴素的 IO第 4~6 行open(dictionary.txt)→readlines→close把整本词典读成一行一个字符串的数组。第 8 行map(strip, lines[27:end])——两个细节藏在这里从第 27 行开始切片直接跳过古腾堡电子书的版权页、标题、START OF EBOOK 等头部元信息strip去掉每行首尾空白避免正则误判。第 10~13 行定义了 4 个行识别器这是整个解析器最聪明的部分——不记状态只记模式isheader(l) ismatch(r^[A-Z\s-_]$, l) # 词条头全大写/空格/连字符 isdefn(l) ismatch(r^Defn:, l) # 定义行以 Defn: 开头 isword(l) ismatch(r^[A-z]$, l) # 纯字母词 getwords(d) filter(isword, split(d, r[^A-z], false)) # 从定义里抽词isheader用正则^[A-Z\s-_]$判断是否可能是一个词条如DEFIGURE、A sharpisdefn判断是否进入定义区getwords先把定义文本按非字母切分再筛出纯字母词供后面构建关系图使用。 小技巧把判断一行是什么封装成独立的小函数主循环会变得极其干净。 第 2 步三个状态变量 一个迷你状态机第 15~19 行dictionary Dict() # 最终结果容器 word false # 当前正在等待定义的单词 defining false # 是否正处于读定义模式 defn # 正在累积的定义文本这 4 个变量构成了一个隐式状态机可以画成三态流转空闲态word false。读到isheader行 → 记住单词名进入待定义态待定义态word有值、defining false。读到isdefn行 → 剥掉Defn:前缀置defining true进入读定义态读定义态defining true。普通行不断拼接到defn遇到空行 → 定义结束写入dictionary[word]两个状态位复位回到空闲态。 第 3 步逐行精讲核心 for 循环第 21~54 行主循环的逻辑可以按三段读① 词条头分支第 22~29 行命中isheader后先查haskey(dictionary, line)只有没收录过的词条才登记防止2. (Mus.)这类带标点变体、或重复合并词条被重复处理然后把word line记下continue跳到下一行——注意没有else每个分支用continue收口这是 Julia 写状态机的惯用清爽姿势。② 定义行分支第 31~40 行命中isdefn时若word ! false说明确实有词条在等定义执行defn 先清空为可能的下一个 Defn 段做准备defining true切到读定义态replace(line, Defn: , )剥掉前缀把剩余内容累进defn。如果word false比如某些附录里孤立的 Defn 行直接忽略。③ 定义累积分支第 42~53 行只要defining为真行是空串 → 定义完整了dictionary[word] defn落袋defining false、word false双复位否则defn $defn $line用空格拼接续行——韦氏词典的定义都是多行折行的这一步把换行还原成词间空格这正是输出 JSON 里定义是一整句的原因。循环结束后第 56~59 行JSON.print把 86036 个键值对写进dictionary.json。以词典中的真实数据为例DEFIGURE → To delineate. [Obs.]These two stones as they are here defigured. Weever. 第 4 步顺手再生成一份定义关系图第 61~82 行脚本的后半段是个惊喜它不满足于单词→定义还想回答每个单词是用哪些词定义的第 61 行unique(keys(dictionary))取出全部词条作为图的节点第 70 行用前面定义的getwords(definition)从定义里抽出所有单词第 75 行_.without(words, node)—— 借_.jl里的without函数把单词自己从列表里剔除避免自环第 77 行map(uppercase, words)全部转大写对齐节点名后写入graph[node]第 69~74 行的try/catch是防御性编程个别畸形定义解析失败时只打印警告并跳过不让整批 8.6 万条数据因一条坏行而崩溃。graph.json里的一条典型记录形如DEFIGURE → [DELINEATE, OBS, STONES, ...]——每个词连着定义它的那些词这可以直接用来做词义相似度、单词接龙甚至用简单词定义复杂词的最小定义集研究。 配角 _.jl作者自制的微工具库_.jl是一个用 Julia 重写 Python underscore 的思路的小模块核心是without求差集without(a::Array, values...) difference(a, values...)顺带还提供了memoize、partial、compose等函数式工具。本脚本只用到它一个函数但这也展示了 Julia 模块化module _ ... end的最小形态。 如何本地运行 main.jl安装 Julia官方二进制或 Julia 集成开发环境见 README.md 的 How to run 一节说明在仓库根目录安装 JSON 包Pkg.add(JSON)确认dictionary.txt与main.jl同目录执行julia main.jl稍等片刻同目录下会生成dictionary.json与graph.json。⚠️ 注意脚本里open(dictionary.txt)用的是相对路径必须在仓库根目录运行否则找不到输入文件。✅ 小结82 行代码的三个可迁移经验模式识别代替状态记忆先为每种行类型写正则识别器第 10~12 行主循环只做识别 → 切换状态可读性极高continue收口的分支结构每个分支处理完即跳走状态机逻辑一眼见底第 21~54 行一鱼两吃同一次遍历产出的中间结果dictionary再派生出一张graph.json语义关系图——解析脚本的终点往往是数据资产的起点。如果你想找一份小、完整、能跑通的文本解析 JSON 生成 图构建的样例代码dictionary 项目的main.jl值得存进你的代码收藏夹。【免费下载链接】dictionaryA JSON representation of Websters Unabridged Dictionary项目地址: https://gitcode.com/gh_mirrors/dictio/dictionary创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考