MySQL实现SCRABBLE单词解扰:支持通配符的查询改造方案
SCRABBLE拼字游戏通配符匹配查询方案
原有纯正则实现的核心逻辑是校验「字符范围合规+单字母出现次数不超手牌持有量」,加入最多2个空白通配符后,需要新增「超量字母可由通配符抵扣」的校验规则,不建议用多层嵌套正则硬写(可读性差、匹配错误率高),可以按三层过滤逻辑改写,完美兼容0-2个通配符的场景。
前置参数拆分
在业务层拼接SQL前,先从输入字符串(例如he?lo)中拆分出固定参数,直接替换到SQL模板中即可:
- 统计通配符数量:即输入字符串中
?的个数,取值范围为0/1/2,例如he?lo对应的通配符数量为1 - 统计实体字母持有量:例如
he?lo去掉问号后的实体字母为h/e/l/l/o,对应持有计数为h:1、e:1、l:2、o:1 - 手牌总长度:实体字母数+通配符数,为可匹配单词的最大长度
改写后的查询语句
以输入he?lo(1个通配符)为例,可直接运行的SQL如下:
SELECT * FROM words WHERE -- 第一层:长度校验:单词至少2个字母,且长度不超过手牌总长度 LENGTH(word) BETWEEN 2 AND 5 -- 第二层:基础格式校验:单词仅由小写英文字母构成 AND word REGEXP '^[a-z]{2,}$' -- 第三层:核心频次校验:所有超量字母的总个数不超过通配符数量 AND ( -- 已持有字母:仅累加超出持有量的部分 GREATEST(LENGTH(word) - LENGTH(REPLACE(word, 'h', '')) - 1, 0) + GREATEST(LENGTH(word) - LENGTH(REPLACE(word, 'e', '')) - 1, 0) + GREATEST(LENGTH(word) - LENGTH(REPLACE(word, 'l', '')) - 2, 0) + GREATEST(LENGTH(word) - LENGTH(REPLACE(word, 'o', '')) - 1, 0) -- 未持有字母:出现多少个就需要占用多少个通配符,直接累加计数 + (LENGTH(word) - LENGTH(REPLACE(word, 'a', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'b', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'c', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'd', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'f', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'g', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'i', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'j', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'k', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'm', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'n', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'p', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'q', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'r', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 's', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 't', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'u', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'v', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'w', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'x', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'y', ''))) + (LENGTH(word) - LENGTH(REPLACE(word, 'z', ''))) ) <= 1 -- 此处替换为实际通配符数量,0/1/2均可支持
逻辑说明
- 通配符数量为0时,查询逻辑和原有正则实现完全一致:超量字母总和必须为0,即单词不能出现未持有字母、每个字母出现次数不能超过持有量
- 通配符数量为1/2时,所有「超出持有量的已持字母个数」+「未持有字母个数」的总和,只要不超过通配符数量即符合规则。例如输入
he?lo匹配helio时,未持有字母i出现1次,超量总和为1,刚好等于通配符额度,可正常返回;匹配helooo时o超出持有量2次,超量总和为2超过通配符额度,会被正常过滤 - 基于字符串长度差的计数方式,比正则回溯匹配的执行效率更高,也不会出现正则贪婪/非贪婪匹配导致的计数错误,切换通配符数量仅需修改最后一行的阈值即可,不需要调整整体校验结构
注意:如果词表存储的是大写单词,将所有REPLACE匹配的字符改为大写,或统一用
LOWER(word)做字段转换即可避免大小写匹配错误。
内容的提问来源于stack exchange,提问作者Rakan AbdelQader
相关产品推荐
相关产品推荐

