【问题标题】:How can I find string matches from an array of characters? ex. given a,n,t find string matches ant, an, tan in a word list table如何从字符数组中找到字符串匹配项?前任。给定 a,n,t 在单词列表表中查找字符串匹配 ant,an,tan
【发布时间】:2012-10-18 02:14:18
【问题描述】:

到目前为止,我的数据库中有 27 个表。 1个单词表(拼字游戏单词表),26个关联表。

Table  Fields
================
word   [id,word]
a      [word_id,count]
b      [word_id,count]
...
z      [word_id,count]

我正在尝试找出给定字符串的匹配词。

例如,如果给定的数组是a,n,t 我想知道:ant, tan, at, ta, an, na

我目前的策略是分解字符串中的每个字母并找到与所有字母匹配的相关单词。

例如:

SELECT word.word
FROM word, a, n, t
WHERE
    word.id = a.word_id OR
    word.id = n.word_id OR
    word.id = t.word_id

但这最终会打印所有包含a,n or t 的单词。

如果我将所有运算符都切换为 AND,我只会遇到一个匹配项:ant

你能帮我解开这个谜吗?

我还关心如何处理字符串中的重复字母。我认为字母关联表中的count 字段可以在这里提供帮助。如果单词是app,则p关联表中的计数将为2。

我是否在关联表的正确轨道上或有更好的方法?

我试图在 php/mysql 中相当有效地处理这个问题。我知道之前有其他人用 C、perl、java 等解决过这个谜题。

【问题讨论】:

  • 你能解释一下你是如何从[a,n,t] 得到你想要的东西的吗? - 对我来说,它看起来像是一个任意的结果列表
  • pa 是如何进入a,n,t 的结果列表的?
  • 也许你最好使用正则表达式^[ant]+$——但不确定这对你的特定问题有多适用。
  • @JanDvorak,哈哈,你是对的。已编辑。
  • @deathApril,是的,a,n,t 是一个任意字符数组作为示例。它可以很容易地成为a,m,t。但生成的单词是可以由相同字符组成的实际单词(在 Scrabble 字典中)。本质上,我想输入一组字符并快速列出可以由给定字符组成的所有匹配单词(使用全部或部分字符)。

标签: php mysql string string-matching


【解决方案1】:

如果你想要一个标准化的方法,那就是:

wordLetters{
  INT wordID,
  CHAR[1] letter,
  INT count,
  PK(wordID, letter)
}

words{
  INT wordID PK,
  VARCHAR(255) word UNIQUE
}

但是这种方法在性能方面有一个严重的问题——即它需要对单词表进行全表扫描。我将假设没有太多字母并建议这种方法:

words{
  INT wordID PK,
  VARCHAR(255) word UNIQUE,
  INT cA KEY,
  INT cB KEY,
  ...
  INT cZ KEY,
  KEY (cE, cT, cA, cO, cI, cN),
  ...
}

查找查询会很长,但它会有效地使用索引,并且无论如何它都是由 PHP 代码生成的:

如果用户有[a,n,t],获取可用的单词为:

SELECT word FROM words WHERE
   cA <= 1 AND cB = 0 AND cC = 0 AND ... AND cY = 0 AND cZ = 0

此查询将(可能)使用“ETAOIN”索引,因为不需要“E”的单词并不多。

此时,性能取决于仅对数据库可用的索引的选择,您始终可以添加更多认为有用的索引(即使在运行时)。


关于数据库索引:

一个普通的索引只是一个排序的项目列表,在列表上构建了一个适当的树,可以进行有效的范围查找(获取从 x 到 y 的所有元素)。

一个普通的索引是由它的排序顺序定义的。排序顺序是:先按某列排序,再按另一列排序,再按另一列排序……

例如,[E,T,A,O,I,N] 索引将对所有单词进行排序:首先是所有不需要E 的单词,然后是所有需要一个E 的单词,然后是所有需要两个E 的单词。 ...需要相同数量Es 的单词将被排序:首先所有不需要T 的单词,然后所有需要它一次的单词,然后所有需要两个Ts 的单词...... .在需要Es 和Ts 数量相同的单词中,不需要A 的单词排在第一位。

如果要求数据库获取所有不需要ET且最多一个'X'的单词,它可以使用该索引来满足前两个要求,然后检查所有单词在E=0, T=0 范围内。

特定的选择,ETAOIN 是基于短语ETAOIN SHRDLU,它按照频率对英语语言中最常见的十二个字母进行排序 - 这意味着如果使用此索引,它应该过滤掉尽可能多的数量字数。

您使用示例RSTLNE。当玩家没有Rs 或Ss 时,将/可能使用此索引。对查找进行基准测试可以告诉您使用每个特定索引节省了多少时间。

您可以使用EXPLAIN EXTENDED 查询来查看哪些索引被考虑并随后用于每个特定查询,以及预计将过滤掉多少行。例如:

EXPLAIN EXTENDED
  SELECT word FROM words
  WHERE cA=0 AND cB<=1 AND cC=0 AND ...

【讨论】:

  • 有趣。您能详细解释一下KEY (cE, cT, cA, cO, cI, cN) 策略吗?那些只是流行的字母吗?当您说我可以根据需要添加索引时,这就是您的意思吗?如在,如果它们也经常使用,添加一个RSTLNE 键?
  • @Ryan 添加了关于索引的说明。
  • 哇,这太棒了。如此简单,它的工作原理!最后一个问题。我无法为多个字段设置键。你能帮我通过ALTER TABLE 查询 ETAOIN 来进行设置吗?
  • dev.mysql.com/doc/refman/5.6/en/alter-table.html。语法为ALTER TABLE words ADD INDEX i_etaoin(cE, cT, cA, cO, cI, cN),其中i_etaoin 是索引名称。如果您不指定索引名称,则会生成一个。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多