当前位置 : 145z游戏站 | 热血传奇 | 技术教程 | 

脚本判断传奇家族名称完整方法服务端检测命令与正则特征匹配实战

热度:
一批角色名摆在面前,要快速分出哪些属于成建制的家族、哪些只是散人。几十个还能靠肉眼,上千个就只能交给脚本。判断的核心不是多高深的算法,而是把家族名的命名习惯拆成程序能读懂的几条规则。

游戏里的家族名常年贴着几类固定特征,抓住这些特征,脚本的命中率就不会低。

一、先看清楚家族名长什么样

符号特征。前缀或包裹用的符号相对固定,常见的有丶丿灬★☆〆ゞメ彡巛艹卩丨°·℡≈ζΨ。这类符号很少出现在普通散人的取名里,是最省事的一道筛子。

后缀特征。成建制的组织名往往以固定词收尾,家族、战队、世家、皇朝、王朝、联盟、军团、帝国、神殿、公会、俱乐部、集团、战团、组织、门派、阁、盟、族都是高频词。名字里带这些字,是家族的概率就往上抬。

词根特征。征战向偏爱傲世、弑神、战魂、龙腾、血煞、屠龙、裁决、霸气;怀旧向偏爱盟重、比奇、苍月、祖玛、赤月、骨灰、昔日;情义向偏爱兄弟、情义、肝胆、聚义、同心、不弃。这些词根反复出现在家族名里,攒成一个词库就能覆盖大半。

结构特征。常见形态是前缀加角色名,比如两到三个字的前缀配一个符号再接一到两个字的角色名;也有整名用方括号、书名号包裹的,像【】『』。前缀一般控制在两到四个字,太长在游戏里显示不全,这本身也是一条判断依据。

字体特征。家族名爱用繁体或异体字,龍、戰、爺、滅、緣、卐这些比简体更常见,偶尔还混火星文。

二、判断的两条路

服务端脚本和外部脚本是两回事,别混着用。

服务端走的是游戏引擎自带的检测命令,它只能回答"这个角色或这个行会在不在我给的名单里",不做语义推测。核心命令有这么几个:CHECKOFGUILD后面跟行会名称,检测当前人物的行会名;CHECKNAMELIST后面跟角色名列表文件,检测当前角色名在不在列表里;CHECKGUILDLIST后面跟行会列表文件,检测当前人物行会在不在列表里;CHECKNAMEIPLIST可以同时比对角色名和登录地址。

外部脚本走文本处理,把名字当字符串分析,靠特征和词库去猜,不依赖名单,也不依赖引擎。

三、服务端命令怎么落地

引擎脚本多用IF判断、ACT动作的结构,判断和动作分开写。想把家族名做成名单判断,先把家族名或角色名写进一个文本文件,每行一个,再在脚本里检测:

[@家族检测]
IF
CHECKGUILDLIST家族名单.txt
ACT
SENDMSG6你所属的行会在名单范围内
ELSEACT
SENDMSG6未识别到名单内的行会

角色的判断同理,把CHECKGUILDLIST换成CHECKNAMELIST,文件换成角色名列表即可。这种做法的优点是准,名单里有什么就是什么;缺点是名单要自己维护,新冒出来的家族不进名单就判不出来,它对"长得像家族但不在名单里"的名字也束手无策。名单模式适合做准入、白名单这类要求确定性的场景,不适合做全量识别。

四、外部脚本的核心是特征库

脚本判得准不准,八成看特征库搭得好不好。至少准备四份数据。

符号集,把上面列的家族符号放进一个集合,逐字符查。
后缀词集,组织类收尾词。
词根集,征战、怀旧、情义几类高频词。
名单库,已知家族名,做精确和近似比对。

维护这几份数据有个技巧,别一次写死。先把到手的名字跑一遍,看哪些被误判,把误判里反复出现的符号或词补进对应集合,跑几轮之后命中率会明显抬上来。

五、正则做第一层过滤

正则擅长处理结构化的东西,比如符号加若干汉字、带方括号的行会名。下面这个函数把几条硬规则叠起来打分:

importre

SYMBOLS=set("丶丿灬★☆〆ゞメ彡巛艹卩丨°·℡≈ζΨ")
ORG_SUFFIX=("家族""战队""世家""皇朝""王朝""联盟""军团"
"帝国""神殿""公会""俱乐部""集团""战团""组织""门派")
ROOTS=("傲世""弑神""战魂""龙腾""血煞""屠龙""霸气"
"兄弟""情义""肝胆""聚义""盟重""比奇""苍月"
"祖玛""赤月""骨灰""昔日")

deffamily_score(name):
name=name.strip()
ifnot(2<=len(name)<=20):
return0
s=0
ifany(cinSYMBOLSforcinname):
s+=40
ifany(sfxinnameforsfxinORG_SUFFIX):
s+=35
ifany(rootinnameforrootinROOTS):
s+=20
ifre.search(r"[【
(
(
『〈
]
.
+
[
】
((『〈].+[】))』〉]"name):
s+=25
ifre.search(r"[\u4e00-\u9fa5]{14}[丶丿灬★☆·°][\u4e00-\u9fa5]{16}$"name):
s+=15
returns

分数到某个阈值就判为家族名。阈值别拍脑袋定,拿实际名单试出来,不同服务器的取名习惯差别不小,同一个分界值搬过去效果可能差很远。

六、近似比对抓马甲

同一个家族的人,前缀通常一致,只有后面的角色名不同。这类靠精确匹配抓不住,要用相似度。标准库里的difflib就够用:

importdifflib

defmatch_family(namefamily_listcutoff=0.8):
hit=difflib.get_close_matches(namefamily_listn=1cutoff=cutoff)
returnhit[0]ifhitelseNone

known=["傲世丶霸刀""傲世丶血剑""昔日〆老兄弟""苍月情义"]
print(match_family("傲世丶孤狼"known))

更稳一点的做法是先抽前缀。把名字里的符号切掉,塞号之前或之后固定长度的片段作为候选前缀,再拿这个片段去和名单里所有家族的前缀比对,公共前缀长度到两三个字就认定是同一家族。这样做对前缀一样、角色名完全不同的情况特别有效,也是实际判断马甲最常用的一招。

七、容易踩的坑

符号兼容。同一批名字在不同登录环境里显示不一样,有的符号会被过滤成空格或直接吞掉。判断之前先清洗一遍,把不认识的符号归一化成占位符再比对,否则同一个家族会被拆成好几类。

繁简和异体。龍和龙、戰和战如果不做映射就是两个词,家族名又偏偏爱用繁体。备一张繁简对照表,比对前统一转换。

散人带符号。有些普通玩家也爱加个符号,单靠符号判会误伤。所以符号只做加权,不单独定生死,必须和后缀、结构一起看。

纯数字和乱码。像纯数字加家族、无意义字母加战队这种,搜不到也记不住,判断时可以降权甚至直接排除。

名单漂移。家族会改名、会拆分、会合并,名单需要定期更新,不然越用越偏。

八、整体流程

把上面几步串起来,一个能用的判断流程大致是这样:先清洗名字,做繁简转换和符号归一化;拿清洗后的结果过正则和特征打分;分数够高直接判为家族;分数居中就去名单库里做近似比对,命中就认定是已知家族的成员;两边都没有结果,再落到人工复核。

规则脚本负责速度和第一层筛除,词库和名单负责准头,近似比对负责把同一家族的马甲串起来。三者叠着用,比单独依赖某一种方式要稳得多,也才经得起大批量角色的检验。
[顶部]