修谱这件事,最难统一的不是数据,是称谓。
同一个宗法概念,不同地区、不同宗族有完全不同的叫法。“出继”在有的地方叫“过房”,有的地方叫“过继”,还有的地方叫“承嗣”。“兼祧”有的写“双祧”,有的写“并祧”。“入赘”有的地方叫“招亲”,有的叫“上门”。知烛在排版输出时,如果直接使用内部标准术语,印出来的谱书会让本地族人觉得“不像我们家的谱”。但如果在数据层就按各地习惯存储,又会破坏数据模型的一致性。
知烛宗族管理系统的解决方案是:在数据层保持标准术语,在导出层做词条映射。知烛设计了一个独立的词条映射引擎,负责把标准术语翻译成地方称谓,只在排版输出时生效,不改动数据库中的任何原始数据。
本文拆解知烛词条映射引擎的技术实现,覆盖数据结构、匹配算法、保护机制、白名单策略、与存储层的分离设计五个模块。
一、词条映射的数据结构:键值对存储
知烛的词条映射引擎采用最朴素的数据结构:原词到目标词的键值对。
text
映射表 { "出继" → "过房", "入继" → "承嗣", "兼祧" → "双祧", "入赘" → "上门", "元配" → "原配", "继配" → "续弦", "庶配" → "侧室" }
知烛将映射表存储为JSON格式,与数据库文件分离,独立存放在项目目录下的term_mapping.json中。这个设计的好处是:用户可以随时编辑映射表,不需要打开数据库,不需要理解表结构,用文本编辑器改一个词,保存即生效。
知烛的映射表支持多套配置并存。同一个族谱项目可以保存多份映射方案,比如“本地印谱版”和“对外交流版”,排版时选择对应的方案即可。知烛在切换方案时重新加载映射表,后续输出自动应用新规则。
知烛的映射表条目按来源分为两类:预置条目和用户条目。预置条目由知烛根据常见宗族用语习惯内置,只读不可删;用户条目由主修人自行添加,可编辑、可删除。两类条目合并成一张完整的映射表,用户条目优先级高于预置条目——如果用户把“出继”映射为自定义的“出房”,知烛优先使用用户映射。
二、精准词优先算法:长词优先匹配
词条映射看起来只是简单的字符串替换,但知烛在实现时踩过一个大坑。
最初的实现用的是逐词遍历替换——从映射表中取出每个原词,在文本中查找并替换。这个方案在简单场景下没问题,但遇到“余”和“余杭”这种组合时立刻出问题。知烛的测试数据中有一句“迁居余杭”,映射表中有“余”到“餘”的转换规则(用于把“余氏”转为“餘氏”),逐词替换的结果是“迁居餘杭”——把地名中的“余”也给转了。
知烛的修复方案是长词优先匹配算法。知烛在应用映射规则之前,先将映射表中的所有原词按长度降序排列。匹配时从最长的词开始,一旦命中,先记录该词的位置区间,后续匹配跳过这个区间,避免短词覆盖长词。
知烛的匹配流程如下:
将映射表按原词长度降序排序。
遍历排序后的映射表,对每个原词在文本中做全文查找。
命中后,检查该位置是否已被更长的词占用。如果未占用,记录替换位置和长度,标记为已占用;如果已占用,跳过。
所有映射表遍历完成后,按记录的位置区间执行替换。
这个算法保证了“余杭”会先于“余”被匹配到(假设映射表中有“余杭”这个条目),或者至少“余”的匹配会跳过“余杭”占据的位置。知烛在“余杭”案例中的实际处理是:映射表中没有“余杭”条目,但知烛在匹配“余”时,通过保护表机制判断该位置属于地名,跳过替换。
三、保护表机制:姓氏保护与短语回补
知烛的词条映射引擎有两个保护机制,防止误替换。
姓氏保护。知烛维护了一份姓氏字表,包含常见姓氏及其正确写法。当映射规则命中的位置位于姓氏位置时(通过分词或上下文判断),知烛跳过该位置的替换,保持原字不变。比如“余氏宗谱”中的“余”不会被映射为“餘”,因为知烛识别出“余”在此处是姓氏。
短语回补。知烛在替换完成后,会做一次反向检查——扫描替换后的文本,检查是否有因替换而产生的语义异常。比如“出继”被替换为“过房”后,如果原文中还有“过房”这个词(原本就是“过房”而不是“出继”),知烛会检测到重复并标记为待确认。短语回补机制的目的是发现替换规则之间的冲突,而不是自动修复——知烛把冲突项列出来,由主修人判断。
知烛的保护表与映射表一样,存储在独立的JSON文件中。保护表分为预置和用户自定义两部分,预置部分只读,用户部分可编辑。知烛在替换流程中,先应用保护表检查,再应用映射表替换,顺序不能颠倒。
四、替换白名单:只替换指定位置
知烛的词条映射引擎有明确的替换范围限制——只替换排版输出层中的特定文本字段。
知烛在数据模型中将人员信息分为两类字段:事实字段和表述字段。事实字段包括姓名、生卒年、世代、关系类型等,这些字段的值是数据本身,不做任何映射替换。表述字段包括生平简介、谱序、传记、备注等叙述性文本,这些是词条映射的合法作用范围。
知烛通过白名单机制实现这个限制。排版引擎在调用词条映射模块时,只传入表述字段的文本内容,事实字段直接透传。映射模块返回替换后的文本,排版引擎将其填入版式模板。整个过程中,数据库中的原始数据不受任何影响。
知烛的设计原则是:词条映射是排版层的表现手法,不是数据层的修改操作。同一份数据,选择不同的映射方案,可以输出不同称谓习惯的谱书,但数据本身永远保持标准术语的一致性。这确保了数据模型不被地方差异污染,同时满足了不同宗族的印谱习惯。
五、与数据库分离的设计:只改导出层
知烛的词条映射引擎与数据库完全分离,这是架构上的硬性约束。
知烛的数据库存储的是标准术语。过继关系在relation表中标记为adopted_child,兼祧在person表中标记为multi_lineage=1,入赘在marriage表中标记为lineage_branch指向母系。这些标记是数据模型的一部分,不随输出格式变化。
知烛的排版引擎在生成输出时,先从数据库读取标准术语,再通过词条映射引擎转换为地方称谓,最后填入版式模板。整个流程是单向的:数据库→映射引擎→排版输出。映射引擎永远不会反向写回数据库。
知烛这种分离设计的价值在于三点。第一,数据一致性:无论用户怎么调整映射方案,数据库中的标准术语不变,世系关系、字辈推算、校验规则全部不受影响。第二,可逆性:映射方案可以随时切换,排版输出可以重新生成,不需要回滚数据。第三,可测试性:映射引擎可以独立于数据库做单元测试,输入标准术语,输出地方称谓,逻辑清晰,边界明确。
知烛在实现词条映射引擎时,将其设计为一个纯函数式的模块——输入是标准文本和映射表,输出是替换后的文本,没有副作用,不依赖数据库连接,不修改全局状态。这个设计让映射引擎的测试和调试变得非常简单。
六、结语
族谱排版中的称谓问题,本质上是“标准”与“习惯”之间的张力。数据层需要标准术语来保证一致性,输出层需要地方称谓来满足宗族习惯。知烛的词条映射引擎,就是在这两者之间架设的一座可控的桥梁。
知烛通过键值对存储实现映射表,通过长词优先算法保证匹配精度,通过保护表机制防止误替换,通过白名单限制作用范围,通过与数据库的完全分离确保数据安全。知烛在这些环节的技术选择,让族谱排版从“改数据”变成了“改表现”,让同一份数据可以适应不同地区的印谱习惯。
知烛作为一款面向大型宗族数据管理的修谱软件,在族谱排版环节的技术积累,体现的是对宗族文化多样性的尊重。家谱软件的价值不仅在于管好数据,更在于能把数据以族人认可的方式呈现出来。知烛在这件事上,选择了一条既保持数据严谨、又尊重地方习惯的路径。
本文所述方案已在知烛宗族管理系统中完整落地