fate: 现代化取名

介绍

最近计划开俩新系列,写写 Beancount 和 Obsidian,顺带整理整理之前的文章 tag,启用封印已久的 Hugo 自带的 分类 功能。在此之前先再水几篇文章,比如今天要介绍的现代化取名工具 fate

参考算法包括:

  • 周易卦象
  • 大衍之数
  • 三才五格
  • 喜用神(平衡用神)
  • 生肖用字
  • 八字吉凶

虽然仓库 README 表示 fate 是「现代科学取名工具」,但「科学」这点还是不敢恭维,从上面特地列出的指标不难看出,所用体系都是偏主观的经验主义哲学,相关理论的形成是滞后的,通过经验总结得出(而非归纳演绎得到)。况且取名这个事情本身就很主观,很难找到普遍适用的标准,即使有,也要受主观印象的制约。

其实我在 2017 年刚出的时候 就关注了,但当时受限于数据库相关知识,尝试没能成功,前几天突然想到了这个。年代久远,软件名字都忘了,于是用 前几日自建的 whoogle 一番搜索,总算是找到了,惊讶地发现作者居然还在更新,而且默认数据库从 MySQL 改成了 SQLite,也不再要求 Golang 环境,比当初容易上手得多,欣然尝试。

运行

参考文档正常安装,下载预编译的二进制文件和数据库即可,建议选择 auto_build 版本,功能最完整。

在 Void 里不报期待地运行,不出所料不支持 musl-libc:

$ ldd ./fate_linux_amd64
		/lib64/ld-linux-x86-64.so.2 (0x7f2c60708000)
        libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7f2c60708000)
Error relocating ./fate_linux_amd64: __memcpy_chk: symbol not found
Error relocating ./fate_linux_amd64: __memset_chk: symbol not found
Error relocating ./fate_linux_amd64: fcntl64: symbol not found

$ libtree -v ./fate_linux_amd64
./fate_linux_amd64
└── libc.so.6 not found
    ┊ Paths considered in this order:
    ┊ 1. rpath:
    ┊ 2. LD_LIBRARY_PATH was not set
    ┊ 3. runpath was not set
    ┊ 4. ld config files:
    ┊ 5. Standard paths:
    ┊    /lib
    ┊    /lib64
    ┊    /usr/lib
    ┊    /usr/lib64
Error [./fate_linux_amd64]: Not all dependencies were found

切换至 Devuan 运行程序,默认在 fate 同级文件夹输出类 JSON 的 name.txt

# 初始化
./fate_linux_amd64 init
# 选择性编辑配置文件
vim config.json
# 获取命令帮助
./fate_linux_amd64 -h
./fate_linux_amd64 help name

# 运行
./fate_linux_amd64 name -l 王 -b "2023/08/22 17:06" -s 女

配置

官方文档做得比较模糊,都是塞在帮助命令或者源码中,简单备注一下,具体的可以参考 example/create_a_name/main.go

{
 "run_init": false,
 "filter_mode": 0,
 "stroke_max": 14,     // 单字最大笔画数
 "stroke_min": 3,      // 单字最少笔画数
 "hard_filter": false,
 "fix_bazi": false,    // 八字修正
 "supply_filter": true,// 三才五格
 "zodiac_filter": true,// 生肖
 "bagua_filter": true, // 八卦
 "regular": true,      // 常用字库
 "database": {
  "name": "fate.db3",  // 默认是 fate,我特地重命名便于把主程序改成 fate
  "driver": "sqlite3", // 也可以用 MySQL,然后填一堆内容
  "show_sql": false,
  "show_exec_time": false
 },
 "file_output": {
  "output_mode": 0,
  "path": "name.txt",
  "heads": [
   "姓名",
   "笔画",
   "拼音",
   "喜用神",
   "八字"
  ]
 }
}

Debug

如果出现报错,默认的输出难以阅读,可以将报错内容保存为 JSON,然后通过 jq 读取:

$ ./fate_linux_amd64 name 王
{"level":"fatal","ts":1692694897.1576245,"caller":"console/name.go:49","msg":"makename failed","error":"get char failed:last name was not inputted","stacktrace":"main.cmdName.func1\n\t/home/runner/work/fate/fate/cmd/console/name.go:49\ngithub.com/spf13/cobra.(*Command).execute\n\t/home/runner/go/pkg/mod/github.com/spf13/cobra@v1.6.1/command.go:920\ngithub.com/spf13/cobra.(*Command).ExecuteC\n\t/home/runner/go/pkg/mod/github.com/spf13/cobra@v1.6.1/command.go:1044\ngithub.com/spf13/cobra.(*Command).Execute\n\t/home/runner/go/pkg/mod/github.com/spf13/cobra@v1.6.1/command.go:968\nmain.main\n\t/home/runner/work/fate/fate/cmd/console/main.go:22\nruntime.main\n\t/opt/hostedtoolcache/go/1.19.4/x64/src/runtime/proc.go:250"}

# 将报错内容保存为 1.json
$ cat 1.json| jq .
{
  "level": "fatal",
  "ts": 1692694897.1576245,
  "caller": "console/name.go:49",
  "msg": "makename failed",
  "error": "get char failed:last name was not inputted",
  "stacktrace": "main.cmdName.func1\n\t/home/runner/work/fate/fate/cmd/console/name.go:49\ngithub.com/spf13/cobra.(*Command).execute\n\t/home/runner/go/pkg/mod/github.com/spf13/cobra@v1.6.1/command.go:920\ngithub.com/spf13/cobra.(*Command).ExecuteC\n\t/home/runner/go/pkg/mod/github.com/spf13/cobra@v1.6.1/command.go:1044\ngithub.com/spf13/cobra.(*Command).Execute\n\t/home/runner/go/pkg/mod/github.com/spf13/cobra@v1.6.1/command.go:968\nmain.main\n\t/home/runner/work/fate/fate/cmd/console/main.go:22\nruntime.main\n\t/opt/hostedtoolcache/go/1.19.4/x64/src/runtime/proc.go:250"
}

筛选

哪怕只使用常用字库,我得到的文件中也包含了三万余条推荐名,一个个手动查看显然不现实,也毫无效率可言,自然需要一些方法来进行筛选。

数据清洗

默认输出的是类 JSON 格式的文件,直接这么看,那不出十分钟就头晕眼花,需要做一下简单处理转换成 CSV,随后爱用什么看就用什么看,Excel 也行,Pandas dataframe 也不错。

示例脚本:

#!/bin/bash
# name-cleanify.sh
echo "姓名","笔画","拼音","喜用神","八字" > header.txt
sed 's/{"name"://g ; s/"笔画"://g ; s/"拼音"://g ; s/"喜用神"://g ; s/"八字"://g ; s/}//g' name.txt > mod.txt
cat header.txt mod.txt > name.csv
rm header.txt mod.txt
# 添加 BOM,否则 Excel 打开会乱码
vim +"set bomb | set fileencoding=utf-8 | wq" name.csv
echo 'Done.'

不良寓意

根据 建议:字库中去掉一些寓意不好的字新增功能计划与需求 的信息,fate 目前暂时么得黑名单(屏蔽特定字)功能,要筛选其实就两个方法:

  • 从输出文件入手:grep / sed / Select-String 一把梭,删除一些听起来就不太好的字
  • 直接禁止生成:打开/连接数据库,删除对应的字

重名

可以参考 docs/chinese_name_query.md,从户籍省份全国两个维度查找重名的人,避开一些烂大街的名字。

打分/辈份字

有辈份字的要求,还要考虑什么卦象和八字,那取名可太简单了,直接从输出中模糊匹配,有没有符合要求的都不一定 (生辰不好的锅)

打分比较玄学,还是得修改数据库,手动标记字重。

尝试

我用 Excel 筛选出了包含 死亡口唇眼丑畜丧笨叼乳胸灾耻妻爬老奶爹他她母父兄弟姐妹奴肉卵把贪 几个字的名字,同时排除了双字笔划之和小于 12 的名字,将结果从 37000+ 缩减到 14000 以内,作为初步筛选来说还不错,黑名单再扩充一下还能去掉几千。

后面就是玄学挑选了,如果非要系统性地筛选,我可以提供一个思路 1

  1. 把名字挑出来做成(密码学意义上的)Python 字典
  2. 用 jieba 给古籍分词
  3. 用破解密码的思想去撞库,撞上了就输出
  4. 最后手动在这些融合了三教九流体系的精选名中进一步筛选

感想

突然想到一段几年前写的文字,脱离语境引用,希望不会引起误解:

那么,人是否需要「姓」和「名」呢?当然不需要,姓名本身只是一个代号。「姓」由于传统因素,有着大姓小姓之分,于是便有了所谓的「百家姓」。姓氏本身只是一个符号,但长期沿用给它带来了不必要的历史地位,部分人们认为根据姓氏和籍贯,便能大致推测一个人的宗族背景。对于阶级固化的地区而言,这是成立的。对于这些人而言,姓氏只是象征身份的一个标志,即使把姓氏进行一对一的映射,全部换成单纯由数字和罗马字母组成的字符串,也能起到同样的作用。考虑到人的行为习惯具有惯性,「用新型命名法替代姓氏」的做法并不能改变阶级固化的现实,又没能带来明显的好处,而在现实社会中,人与人之间的差异尚未小到可以忽略不记,采用某种特定的「命名法」是必要的。从这一角度,人需要一个「代号」,而遵循传统,这个代号是「姓名」。当然,这里没有讨论「取消姓但保留名」的做法,我认为道理是一样的,对于阶级固化的社会,人们既然不能通过「姓」来判断家庭关系,就势必会去寻找替代品,而不是不再关注阶级分化。从社会层面讲,在没有国家没有政府也没有阶级分化的共产主义实现(if possible at all)之前,恐怕还是存在政府这种东西。「姓氏」对于管理而言可有可无,但不存在主动改变的驱动力,原因同上。若是想要解构「姓氏」与「阶级」的关联,便需要一种不可继承、不可追溯、近乎随机的代号系统,但这样一种系统的存在本身,便是与「姓氏」、「冠姓权」以及下文即将提到的「家庭」有所冲突的。

废话这么多,总结起来就仨字:做人难。 甚至难到还没出生就要经历取名的老大难问题。


  1. 后来发现古代先哲早就想到了这点,素有「女诗经,男楚辞,文论语,武周易」的说法。 ↩︎

Vinfall's Geekademy

Sine īrā et studiō