【问题标题】:Word Pattern Finder单词模式查找器
【发布时间】:2017-06-17 10:35:05
【问题描述】:

问题:查找所有遵循模式的单词(独立于用于定义模式的实际符号)。

几乎与本网站所做的相同:http://design215.com/toolbox/wordpattern.php

输入如下模式:ABCCDE
这会找到像“血腥”这样的词, “小猫”和“山谷”。上面的模式不会找到像这样的词 “茴香”或“嬉皮士”,因为这需要模式是 ABCCBE。

请注意:我需要该算法的一个版本,它可以找到像“fennel”或“hippie”这样的词,即使是 ABCDE 模式。

更复杂的是,可以在搜索模式的任何位置添加已知字符,例如:cBBX(其中 c 是已知字符)将产生cees、coof、cook、cool ...


到目前为止我所做的事情: 我找到了这个答案 (Pattern matching for strings independent from symbols) 几乎完美地解决了我的问题,但是如果我为需要比较的每个单词分配一个整数,我会遇到两个问题。

第一个是我可以使用的唯一数字的数量。例如,如果模式是 XYZABCDEFG,则等效的数字模式将是 1 2 3 4 5 6 7 8 9,然后呢? 10?考虑一下我会使用数字 0 来表示已知字符(例如,aBe --> 010 --> 10)。使用十六进制数字会使问题更进一步,但不会解决它。

第二个问题是模式的最大长度:Java 中的 Long 是 19 位长,我不需要限制我的模式(尽管我认为不存在一个包含 20 个不同字符的单词)。

为了解决这些问题,我可以将模式的每个数字存储在一个数组中,但是它变成了数组到数组的比较而不是整数比较,因此需要更多的时间来计算。

附带说明:根据所使用的算法,哪种数据结构最适合存储字典?我正在考虑使用散列映射,将每个单词转换为其等效的数字模式(假设没有已知字符)并将此数字用作散列(当然,会有很多冲突)。这样,搜索将首先需要匹配数字模式,然后扫描结果以找到所有在正确位置具有已知字符的单词(如果存在于原始搜索模式中)。

此外,字典不是静态的:可以添加和删除单词。

编辑:

这个答案 (https://stackoverflow.com/a/44604329/4452829) 效果很好,而且速度很快(在匹配模式之前测试相等的长度)。唯一的问题是我需要该算法的一个版本,即使使用 ABCCDE 模式也能找到像“fennel”或“hippie”这样的词。

我已经实现了一种检查已知字符的方法。

编辑 2:

好的,通过检查模式中的每个字符是否大于或等于当前单词中的相应字符(标准化为临时模式)我几乎完成了:它正确匹配搜索模式 ABCA 带有单词 ABBA 并且它正确地忽略了单词 ABAC。剩下的最后一个问题是,如果(例如)模式是 ABBA,它将匹配单词 ABAA,这是不正确的。

编辑 3:

嗯,不是很漂亮,但它似乎可以正常工作(我使用 Python,因为它的编码速度很快)。此外,搜索模式可以是任何符号序列,使用小写字母作为固定字符,其他所有字符作为通配符;也无需将每个单词转换为抽象模式。

 def match(pattern, fixed_chars, word):
    d = dict()
    if len(pattern) != len(word):
        return False
    if check_fixed_char(word, fixed_chars) is False:
        return False
    for i in range(0, len(pattern)):
        cp = pattern[i]
        cw = word[i]
        if cp in d:
            if d[cp] != cw:
                return False
        else:
            d[cp] = cw
        if cp > cw:
            return False
    return True

【问题讨论】:

  • 英文单词少于200,000个,看起来很多,其实不然。遍历它们并针对模式测试它们应该是您的第一次尝试。如果这太慢了,那么你有一个更具体的问题。
  • 牛津英语词典有超过 600,000 个单词。无论如何,我会在接下来的几天内尝试按照您的建议进行操作。
  • 另外,我想要一个足够快的算法来检查姓名列表(我找到了一个 Facebook 名字列表,它有超过 400 万个名字)。编辑:哇,那会很有趣(hackreports.com/2013/05/…

标签: algorithm language-agnostic pattern-matching wildcard


【解决方案1】:

很久以前,我写了一个解密码的程序,它基于相同的概念(生成单词模式,例如“kitten”和“valley”都映射到“abccde”。

我的技术确实涉及按模式生成一种单词索引。

核心抽象函数如下:

#!python
#!/usr/bin/env python
import string

def abstract(word):
    '''find abstract word pattern
       dog or cat -> abc, book or feel -> abbc
    '''
    al = list(string.ascii_lowercase)
    d = dict
    for i in word:
        if i not in d:
            d[i] = al.pop(0)
    return ''.join([d[i] for i in word])

从那里构建我们的索引非常容易。假设我们有一个类似 /usr/share/dict/words 的文件(常见于类 Unix 系统,包括 MacOS X 和 Linux):

#!/usr/bin/python
words_by_pattern = dict()
words = set()
with open('/usr/share/dict/words') as f:
    for each in f:
        words.add(each.strip().lower())

for each in sorted(words):
    pattern = abstract(each)
    if pattern not in words_by_pattern:
        words_by_pattern[pattern] = list()
    words_by_pattern[pattern].append(each)

...在我的笔记本电脑上花费不到两秒钟的时间,大约 234,000 个“单词”(尽管您可能希望为您的应用程序使用更精确或受限的单词列表)。

此时另一个有趣的技巧是找到最独特的模式(返回尽可能少的单词)。我们可以这样创建模式的直方图:

histogram = [(len(words_by_pattern[x]),x) for x in words_by_pattern.keys()]
histogram.sort()

我发现这给了我:

8077    abcdef
7882    abcdefg
6373    abcde
6074    abcdefgh
3835    abcd
3765    abcdefghi
1794    abcdefghij
1175    abc
1159    abccde
925     abccdef

请注意,abc、abcd 和 abcde 都在前十名中。换句话说,最常见的单词字母模式包括所有在 3 到 10 个字符之间没有重复的字母模式。

您还可以查看直方图的直方图。换句话说,有多少模式只显示一个单词:例如 aabca 只匹配“eerie”,aabcb 只匹配“llama”。有超过 48,000 种模式只有一个匹配的单词,近 6000 个模式只有两个单词等等。

注意:我不使用数字;我使用字母来创建模式映射。

我不知道这是否对您的项目有帮助;但这是非常简单的 sn-ps 代码。 (它们故意冗长)。

【讨论】:

  • 顺便说一句,这些来自我的程序;我只是为这个答案重写了这些。
【解决方案2】:

这可以通过使用正则表达式轻松实现。 例如,以下模式匹配任何具有ABCCDE 模式的单词:

(?:([A-z])(?!\1)([A-z])(?!\1|\2)([A-z])(?=\3)([A-z])(?!\1|\2|\3|\5)([A-z])(?!\1|\2|\3|\5|\6)([A-z]))

这个匹配ABCCBE:

(?:([A-z])(?!\1)([A-z])(?!\1|\2)([A-z])(?=\3)([A-z])(?=\2)([A-z])(?!\1|\2|\3|\5|\6)([A-z]))

要涵盖以上两种模式,您可以使用:

(?:([A-z])(?!\1)([A-z])(?!\1|\2)([A-z])(?=\3)([A-z])(?(?=\2)|(?!\1\2\3\5))([A-z])(?!\1|\2|\3|\5|\6)([A-z]))

走这条路,您的挑战将是根据您使用的字母符号生成上述正则表达式模式。 请注意,如果需要不区分大小写,则在使用这些时可能需要使用 i Regex 标志。

有关正则表达式的更多信息,请查看:
Look-around
Back-referencing

【讨论】:

  • 是的,我想到了正则表达式模式,但由于生成正则表达式模式的问题,我把这个想法放回了所有想法的队列中。无论如何,想法越多越好。我会做更多的实验。
猜你喜欢
  • 2013-07-18
  • 1970-01-01
  • 1970-01-01
  • 2012-12-05
  • 1970-01-01
  • 2018-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多