如何编写JavaScript正则实现Hangman猜词的字符使用次数限制匹配
Hangman 谜题正则匹配方案
问题核心
原有正则仅校验空位字符是否在可选库范围内,没有限制单个字符的总出现次数,会匹配到同字符超量的错误结果(比如示例中可选库o仅1个配额,却匹配到含2个o的alloo)。
实现原理
在原有匹配模式前追加一组负向先行断言,对可选库中的每个字符,单独限制其在整个单词中的总出现次数不得超过可选库中的存量,该逻辑天然兼容模式中已存在的固定字符——断言会从单词起始位置扫描全词统计字符数,固定位置的字符会被自动计入配额消耗。
可直接运行的改造代码
import raw from "./static/wordlist.txt"; /** * 构造Hangman匹配正则 * @param {string} letters 待匹配单词模式,如下划线占位的"___o_" * @param {string} bank 可用字符库,如"llaory",字符重复次数代表可用配额 * @returns {RegExp} 匹配符合条件单词的正则 */ function buildHangmanReg(letters, bank) { // 1. 统计可用字符库中每个字符的最大允许出现次数 const charLimit = {}; for (const c of bank) { charLimit[c] = (charLimit[c] || 0) + 1; } // 2. 为每个字符生成负向先行断言:禁止该字符出现次数超过配额 const assertions = []; for (const [char, max] of Object.entries(charLimit)) { // 正则含义:如果全词中char出现次数 >= max+1,直接判定匹配失败 assertions.push(`(?!(?:[^${char}]*${char}){${max + 1}})`); } // 3. 拼接原有字符匹配规则 const charPattern = letters.replace(/_/g, `[${bank}]`); // 4. 组合成最终正则,\b匹配单词边界 return new RegExp(`\\b${assertions.join('')}${charPattern}\\b`, 'g'); } // 示例调用 const pattern = "___o_"; const charBank = "llaory"; const reg = buildHangmanReg(pattern, charBank); fetch(raw) .then(res => res.text()) .then(wordListText => { const matchResult = wordListText.match(reg); console.log(matchResult); // 示例输出:['alloy'],超量的'alloo'会被自动过滤 });
逻辑验证(以题目示例为例)
- 统计可选库
llaory的字符配额:l:2, a:1, o:1, r:1, y:1 - 生成对应断言:
- 限制
l最多出现2次:(?!(?:[^l]*l){3}) - 限制
a最多出现1次:(?!(?:[^a]*a){2}) - 限制
o最多出现1次:(?!(?:[^o]*o){2}) - 限制
r最多出现1次:(?!(?:[^r]*r){2}) - 限制
y最多出现1次:(?!(?:[^y]*y){2})
- 限制
- 匹配校验:
alloy:各字符出现次数均未超配额,匹配成功alloo:o共出现2次,触发o对应的负向断言,匹配失败
注意事项
如果可选库中包含]、-、^这类正则特殊字符,需要提前对字符做正则转义处理;常规小写英文字母场景可直接使用上述代码。
内容的提问来源于stack exchange,提问作者James Huang
相关产品推荐
相关产品推荐

