使用方法
- 在「目标单词或短语」里填 listen(页面默认示例)。只有 A–Z 字母进入计算,空格、连字符、数字、标点都会被忽略,大小写也不区分——所以
Listen与listen的签名完全相同。 - 在「词库」里每行放一个英文词,默认预置了 32 个词。也可以直接把一整段词表粘进去,工具会按「非字母字符」切分,空格、逗号、换行、制表符都能当分隔符。
- 「最短词长」默认 2,含义是参与匹配的词至少两个字母。这一步同时过滤词库和结果:1 个字母的
a、i会被挡在外面。 - 「最多组合词数」默认 2:既能找出单词变位词,也能找出两个词拼成的组合。设成 1 就只看单词;设成 3、4 会继续尝试三词、四词组合。
- 「必须用完全部字母」默认勾选。勾上时结果必须恰好使用目标的全部字母;取消勾选则放宽为「这些字母能拼出的词」,会顺带把
in、is这类短词也列出来。 - 点「开始求解」,变位词求解会把结果写进下方表格:默认显示 12 行,超出后出现「加载更多」;「复制对照表」把整张表以制表符(TSV)复制到剪贴板,「导出 CSV」下载带 BOM 的表格文件,Excel 打开不会乱码。
这个变位词求解能解决什么问题
一是查同一组字母能拼出的所有单词。拿到 listen 这 6 个字母,人脑很难穷举出 silent、enlist、inlets、tinsel 这四兄弟,而这个变位词求解在本地一次排序就全部列出来。
二是验证两个词是不是变位词。把其中一个词填进目标框、另一个词放进词库,命中了就是。判断依据是字母多重集是否相同,和词义、词性、发音都无关。
三是拼字类游戏的助手。拼字游戏、填字游戏、Hangman 里经常需要「用给定的几个字母凑出合法词」,把游戏词库粘进来、把手里字母填进目标框即可按长度筛。
四是短语变位词与文字游戏。把「最多组合词数」调到 3 或 4,可以试着拆解 eleven plus two 与 twelve plus one 这类短语变位词——两者签名都是 eeellnopstuvw。
本页不做这些事:不做发音相近检索(那是押韵工具的事)、不做词典释义、不做跨语言翻译、不做词形还原(run 和 running 不会被当成同一个词)。要查押韵词请用页面底部的「押韵词查询」,要按游戏词典校验拼写请用「拼字游戏词查询」。
求解原理:变位词求解的排序签名与字母多重集剪枝
核心只有一行:sig(w) = [...w.toLowerCase()].filter(c => c >= 'a' && c <= 'z').sort().join('')。把一个词的所有字母取出来、按 a 到 z 升序重新排列,得到的字符串就是这个词的签名。例如 listen 排完是 eilnst,silent 排完也是 eilnst。
为什么签名相同就等价于互为变位词?因为两个词是变位词的定义就是「每个字母出现的次数完全相同」。对字母做一次稳定排序,等于先按字母分桶、再按 a–z 顺序拼接;只要两张字母频次表逐项相等,拼出来的字符串必然逐位相等。反过来,签名逐位相等也意味着频次表逐项相等。所以「排序后字符串相等」是变位词关系的充要条件,不是近似判断。这个做法本质上是计数排序的一个特例,比较的是 26 个字母桶的计数。
为什么不用全排列?6 个互不相同的字母有 6! = 720 种排列,逐个生成再去词库里查,等于把每个词展开成 720 次比较。签名法换了个方向:词库里每个词各排序一次建表,查询时只算一次目标签名再查表。词库 100 个词是 100 次排序,10000 个词是 10000 次排序,查询始终是一次哈希查找。
多词组合怎么处理。把「签名」从单个词推广到一组词:若干个词拼在一起的签名,就是它们全部字母一起排序。于是枚举时用一个字母多重集剪枝——每加入一个词,先检查累计字母是否仍然「不超过目标字母的库存」:目标 listen 只有一个 l、一个 n,那么 lentil(两个 l)和 linen(两个 n)在第一步就会被剪掉,根本不会进入后续枚举。默认词库 32 个词里,被这步剪掉的是 stone(含 o)、linen、lentil 这 3 个,剩下 29 个可用词。
关键参数为什么这样取。「最短词长」下限取 2,是因为英文里真正被广泛使用的单字母词只有 a 和 i,放进结果只会稀释有效信息;上限取 10,是因为目标字母上限只有 20 个,词长超过 10 的词在多数查询里根本放不下。「最多组合词数」上限取 4,是因为组合数按 C(n,k) 增长:20 个字母时四词组合的组合上界已达 4845 种,再往上只会让枚举变慢而几乎找不到真结果。
字符处理上,本页只认 ASCII 基本拉丁字母两个区间:大写 U+0041–U+005A、小写 U+0061–U+007A,二者在 UTF-16 里各占 1 个码元。
完整示例(数值仅作演示)
示例条件与页面打开时的默认值完全一致:目标 listen、词库 32 个词、最短词长 2、最多组合词数 2、勾选「必须用完全部字母」。实测过程与结果:
- 目标归一化后是
listen,签名 eilnst,共 6 个字母且互不重复,对应6! = 720种排列; - 词库 32 个词中,
stone、linen、lentil因字母超出库存被剪掉,可用词 29 个; - 命中 7 条:单词 4 条 + 双词 3 条(原词
listen自身被剔除,否则每次查询都会秒回自己); - 单词结果按字母序为
enlist、inlets、silent、tinsel; - 双词结果为
in + lets、is + lent、it + lens,三条都恰好用满 6 个字母; - 在同样条件下把「最多组合词数」调到 3,三词组合的条数是 0——6 个字母要切成 3 个词,平均每词 2 个字母,而词库里两字母词只有
in、is、it,它们都含i,凑不满。
顺手把词库按签名分个组,就能看出「一个签名对应一个变位词家族」:
| 签名 | 词数 | 家族成员 |
|---|---|---|
eilnst | 5 | enlist、inlets、listen、silent、tinsel |
ilst | 3 | list、silt、slit |
eils | 2 | isle、lies |
eist | 2 | site、ties |
ent | 2 | net、ten |
输入范围与对照表
四个可控参数的范围与越界后的表现:
- 目标字母 1~20 个。超过 20 个时页面直接报错拒绝,不会硬算。0 个字母(例如只填了「你好123」)同样拒绝,并提示只识别 A–Z。
- 最短词长 2~10 的整数。填 1、填小数、留空都会被拒绝;填 11 以上也拒绝,因为目标最多 20 个字母,超长词没有匹配空间。
- 最多组合词数 1~4 的整数。1 = 只看单词;2 = 单词 + 两词;3、4 依次放开。词库无上限,但超过 5 万行时建表会有可感延迟。
- 结果上限 5000 条。超过就截断并在提示区说明,建议先缩小「最多组合词数」或勾上「必须用完全部字母」。
下表的「组合上界」按一个宽松假设给出:目标有 n 个字母,可用词池最多 n 个,于是两词组合最多 C(n,2)、三词最多 C(n,3)。实际因为有字母多重集剪枝,枚举量远小于这个上界(示例里 29 个可用词、双词上界 406,实测只命中 3 条)。
| 目标字母数 | 全排列 | 双词组合上界 | 三词组合上界 | 四词组合上界 |
|---|---|---|---|---|
| 6(默认示例) | 720 | 15 | 20 | 15 |
| 8 | 40320 | 28 | 56 | 70 |
| 10 | 3628800 | 45 | 120 | 210 |
| 12 | 4.79×108 | 66 | 220 | 495 |
| 16 | 2.09×1013 | 120 | 560 | 1820 |
| 20(上限) | 2.43×1018 | 190 | 1140 | 4845 |
这张表解释了为什么要把目标限制在 20 个字母:8 个字母的全排列已经是 40320 种,12 个字母逼近 4.79 亿——暴力枚举字符串的思路早就不可行了,签名法的价值正体现在这里。
结果边界与精度说明
下面几条不是「限制」,而是刻意设定的边界,知道了就不会把结果用错:
- 只认 ASCII 字母。重音字母
é(U+00E9)、全角A(U+FF21)、希腊α(U+03B1)、西里尔а(U+0430)都会被当成非字母直接丢弃,不参与签名。所以café在本页等价于caf。 - 大小写被拉平。签名阶段统一走
toLowerCase(),Silent、SILENT、silent是同一个签名。输出里词一律按小写展示,不保留你输入词库时的原始大小写。 - 原词会被剔除。目标是单个词时,结果中不含它自己;这样「查一个词」不会每次都被自身占掉第一行。若想看到它,把目标换成它的变位词即可(填
silent就能看到listen)。 - 只比字母多重集,不比别的。不区分元音辅音、不看词义、不看词根。
run和nur若都在词库里就会被判为变位词,哪怕后者不是一个真实单词——本页不做拼写校验。 - 不做词形还原。
run与running字母数量不同,永远不会互相命中;复数lines与单数line同理。需要处理词干请先用词形还原工具预处理词库。 - 结果排序是确定的。先按词数升序,词数相同时按整串字母序,词内多个词也按字母升序排列。所以同一份输入每次求解顺序完全一致,不会跳动。
- 短语会被当作一整串字母。填
eleven plus two时,空格被忽略,签名是eeellnopstuvw(13 个字母,其中e出现 3 次、l出现 2 次);twelve plus one签名完全相同,这正是那对著名短语变位词的判据。 - 组合数与命中数是两回事。提示区里的「可用词」是词库里字母够用的词数,「命中结果」才是实际拼成功的条数。词库越大,前者越大,后者未必变多。
常见问题
结果里为什么找不到目标词本身?
因为工具会主动剔除原词。目标是 listen 时,词库里的 listen 会被跳过,剩下 4 个单词结果。这样设计是因为几乎没有人想看到「输入什么就回什么」。想反过来看到它,把目标换成 silent,结果里就会出现 listen。
词库里的 stone、linen 为什么一条都没出?
它们的字母超出了目标的库存。stone 含 o 而目标是 listen 不含 o;linen 有两个 n、lentil 有两个 l,而目标各只有一个。字母多重集剪枝在加入这个词的第一步就判定"超量",直接跳过,所以它们连一次排序都不会参与。
怎么手工验证两个词互为变位词?
各自把字母排序再比较即可。listen → eilnst,silent → eilnst,两个字符串完全一样,所以互为变位词;list → ilst 与 listen → eilnst 长度都不同,显然不是。注意排序前要统一小写,并且只保留 a–z 字母。
不勾「必须用完全部字母」会变成什么样?
判定条件从「签名完全相等」放宽成「字母是该签名的子多重集」,相当于从"找出全部字母的排列"变成"这些字母能拼出哪些词"。示例里 32 词词库下会多出 in、is、it、line、list 等大量短词。做拼字游戏时这个模式更实用,做「严格变位词」时记得勾回去。
eleven plus two 和 twelve plus one 为什么能互相转换?
因为空格被忽略后,两串字母完全相同:e 3 个、l 2 个,v n p u s t w o 各 1 个,签名都是 eeellnopstuvw。把目标的「最多组合词数」设为 3,词库里同时放上 eleven、twelve、plus、two、one,就能看到两组词互相命中。
词库要放多大才够用?会不会卡?
本页预置的 32 词只是演示用的迷你词库,真实需求建议粘一份两万词左右的常用词表。建表成本是「每个词排一次序」,两万词在普通笔记本上是毫秒级;查询本身是一次哈希查找。真正限制速度的是「最多组合词数」,它决定枚举量,而不是词库大小。
为什么最短词长的下限是 2 而不是 1?
英文里被广泛使用的单字母词只有 a 和 i。把它们放进来,任何含这两个字母的目标都会多出「x + a」「i + y」这类没有信息量的组合,而真正的变位词会被淹没。下限设 2 是精度与噪声之间的取舍,如果你确实要处理缩写表,可以自己把单字母词从词库里删掉。
支持中文、日文或带重音的欧洲语言吗?
不支持。签名阶段只保留 ASCII 的 U+0041–U+005A 与 U+0061–U+007A,其余字符一律丢弃。中文没有"字母多重集相同"这种关系——汉字是语素文字,不是拼音文字,强行按码位排序没有语言学意义。日文假名、希腊字母、西里尔字母同样不在处理范围内。
相关工具
- 拼字游戏词查询:按游戏词典校验一个词是否合法,配合本页的字母组合结果使用。
- Wordle 助手词查询字母:按已知字母位置与排除字母筛 5 字母词,思路和签名法互补。
- 押韵词查询:按韵脚而不是字母集合匹配,找的是发音相近的词。
- Hangman 词生成器:给猜词游戏出题,可按词长与难易度筛选。
- 词搜索生成器:把这些字母排进字母方阵做成找词游戏。
- 填字游戏谜题生成器:把词库批量变成交叉填字题面。
- 实用工具:查看全部实用工具。