【问题标题】:Fastest way to lookup pattern matching words in java在java中查找模式匹配词的最快方法
【发布时间】:2020-03-21 04:08:06
【问题描述】:

给定一个总字数在 100,000-500,000 之间的单词词典,查找模式/掩码的最快方法是什么?其中 '-' 是一个未知字母,即 s--t- 将返回 salts、salty、scats、scots 等...

目前使用的 trie 非常适合填充了首字母的单词,但是当存在诸如 ---st 或 -tr- 之类的模式时,trie 的好处就完全丧失了。

我正在搜索的单词基本上是均匀分布的,其中第一个字母被填满,而那些没有。

将单词加载到 SQL 数据库然后使用 SQL 通配符搜索功能是否有意义?或者我只是手动搜索每个可能的字母组合以查找空白字母的哈希图呢?

如果您能提供任何见解,我们将不胜感激。

【问题讨论】:

  • 我想你可以用倒序的每个单词的字母来镜像字典。
  • 这是一个好主意,但是在任何一方都没有前导字母的查找(我应该提到这一点)。我现在将尝试实现镜像,这肯定会节省一些时间
  • 分析节省的时间是个好主意。有时,即使有最好的逻辑,这样的事情也很少或根本没有用。我认为 SQL 会是更好的选择。
  • 我能想到的加快搜索速度的唯一方法是先检查字典中单词的长度,然后比较字母。否则,您必须浏览整个字典。

标签: java string performance lookup trie


【解决方案1】:

以下小方法利用String#matches() 方法以及动态创建的Regular Expression,该方法基于搜索条件字符串中提供的通配符。它将返回一个字符串列表 (List<String>),其中包含与提供的条件字符串匹配的任何单词。

单词列表 file 我运行搜索条件字符串 ("s--t-") 通过(使用 BufferedReader(FileReader))包含 370,108 个单词,并且通常在大约 250 毫秒或 0.25 秒(平均)。

对于通配符,最常用的通配符是星号 (*),它通常表示一串字符中的零个或多个字符,以及问号 (? ),通常代表任意一个字符。您显然想使用连字符 (-) 代替通常的问号,这是可以的。提供的方法可以根据您的特定目的处理同一条件字符串中的所有三种通配符类型(*?-)。 p>

public static List<String> searchForWord(String dictionaryFilePath, 
                                         String searchCriteria) {
    // This method ignores letter case!
    List<String> foundList = new ArrayList<>();  // To hold all found words.

    // Convert the supplied criteria string to a Regular Expression 
    // for the String#matches() method located in the 'while' loop.
    String regEx = searchCriteria.replace("?", ".").replace("-", ".").replace("*", ".*?").toLowerCase();

    // 'Try With Resources' use here to auto-close the reader.
    try (BufferedReader reader = new BufferedReader(new FileReader(dictionaryFilePath))) {
        String line = "";
        while ((line = reader.readLine()) != null) {
            line = line.trim().toLowerCase();
            if (line.matches(regEx)) {
                foundList.add(line);  // There's a match...add to the List.
            }
        }
    }
    // catch Exceptions (if any).
    catch (FileNotFoundException ex) {
        System.err.println(ex);
    }
    catch (IOException ex) {
        System.err.println(ex);
    }
    return foundList;  // Return the List.
} 

要使用这种方法:

List<String> list = searchForWord("WordFile.txt", "s--t-");
for (String str : list) {
    System.out.println(str);
}

从我使用的单词列表中找到的匹配项:

saeta    saite    saith    sakti    salta
salts    salty    santa    santo    santy
saute    sauty    scats    scatt    scote
scots    scott    scuta    scute    scuts
scyth    seats    sects    seity    senti
sents    septa    septi    septs    serta
sesti    sexto    sexts    sheth    shita
shits    shote    shots    shott    shute
shuts    sidth    sifts    silts    silty
sinto    sintu    sitta    sixte    sixth
sixty    skate    skats    skete    skite
skits    skyte    slate    slath    slats
slaty    slete    slite    slits    slote
sloth    slots    sluts    smeth    smite
smith    smote    smuts    smyth    snath
snite    snits    snitz    snots    softa
softs    softy    sooth    soots    sooty
sorts    sorty    south    sowte    spate
spath    spats    spete    spite    spits
spitz    spots    sputa    spute    sruti
state    stats    stets    stite    stith
stott    suets    suety    suite    suits
suity    sutta    swath    swati    swats
swith    swots    syftn

【讨论】:

  • 这个解决方案效果很好。我通过不将所有单词插入单个单词列表而是为不同的单词长度设置一个单独的单词列表来加快速度。所以有一个长度为 4,5,6 等的字符串列表.....
猜你喜欢
  • 2015-09-06
  • 1970-01-01
  • 1970-01-01
  • 2011-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-09
  • 1970-01-01
相关资源
最近更新 更多