是否存在更高效的正则表达式用于解决Wordle谜题?
我存了一份全5字母英文单词的列表,玩Wordle卡壳时用来检索,顺便在BBEDIT里练正则表达式,挺合适的。
Wordle的规则对应三种匹配条件:
- 字母必须在单词里(不管位置)
- 字母绝对不在单词里
- 字母不仅在单词里,位置还完全正确
条件3很好实现,比如开头猜了“crone”,发现n的位置对,正则就写:
...n.
加条件2也简单,排除那些不用的字母:
^(?!.*[croe])...n.
如果下一个猜的是“burns”,知道答案里有s,正则改成:
^(?!.*[croebur])(?=.*s)...n.
(这里可以去掉重复的^,断言是零宽的,不用多次锚定开头)
要是还知道s不在最后一位,就改成:
^(?!.*[croebur])(?=.*s)...n[^s]
再猜“stone”后知道答案里有t,正则又变成:
^(?!.*[croebur])(?=.*s)(?=.*t)sa.n.
这么写是能跑,但后来猜“wimpy”发现答案里有i,就得再加个(?=.*i),感觉太啰嗦。我试过用字符组^(?=.*[ist]),但它只认包含任意一个字母的单词,不是所有都得有的情况。
解决办法
当然有更高效的写法!其实正则里实现“必须包含所有指定字母”,标准写法就是用多个正向预查,但可以优化得更简洁:
紧凑的多预查写法
不用纠结每个字母单独写(?=.*x),但要记住去掉重复的^(预查是零宽度的,不需要反复锚定开头)。比如要同时包含i、s、t,就写成:^(?=.*i)(?=.*s)(?=.*t)...这看起来是多个预查,但其实是正则里处理“同时满足多个包含条件”的常规操作,对于5字母单词来说,性能完全没问题,而且可读性强,比花里胡哨的技巧实用多了。
针对固定长度单词的小优化
因为你的单词都是5位,最后可以加上$锚定结尾,避免匹配到更长的内容,比如结合位置约束的完整写法:^(?!.*[croebur])(?=.*i)(?=.*s)(?=.*t)sa.n.$
别担心这种写法效率低,正则引擎处理这种短单词的预查速度极快,完全不影响检索体验,而且比其他复杂写法更容易维护——毕竟玩Wordle的时候谁也不想写太绕的正则耽误时间对吧?
内容的提问来源于stack exchange,提问作者brianfit

