【问题标题】:Java: Search in HashMap keys based on regex?Java:基于正则表达式在 HashMap 键中搜索?
【发布时间】:2009-05-18 20:57:48
【问题描述】:

我正在使用 HashMap 构建同义词库来存储同义词。

我正在尝试基于正则表达式搜索单词:该方法必须将字符串作为参数并返回结果数组。这是我的第一次尝试:

public ArrayList<String> searchDefinition(String regex) {
    ArrayList<String> results = new ArrayList<String>();

    Pattern p = Pattern.compile(regex);

    Set<String> keys = thesaurus.keySet();
    Iterator<String> ite = keys.iterator();

    while (ite.hasNext()) {
        String candidate = ite.next();
        Matcher m = p.matcher(candidate);
        System.out.println("Attempting to match: " + candidate + " to "  + regex);
        if (m.matches()) {
            System.out.println("it matches");
            results.add(candidate);
        }
    }   

    if (results.isEmpty()) {
        return null;
    }
    else {
        return results;
    }
}

现在,这不像我预期的那样工作(或者我可能错误地使用了正则表达式)。如果我在 hashmap 中有以下键:

cat, car, chopper

然后通过调用searchDefinition("c")searchDefinition("c*") 我得到null

  1. 如何按预期进行这项工作?
  2. 是否有比 HashMap 更好的数据结构来保存同义词库所需的 graph? (只是好奇,至于这个作业我们被要求使用 Java Collection Map)。
  3. 我在上面的代码中还有什么不恰当的地方吗?

谢谢, 丹

编辑:我已经更正了这个例子。即使我使用正确的大小写它也不起作用。

【问题讨论】:

  • 克林特有答案。但请注意,使用“c*”调用 find() 将匹配 any 条目——因为所有条目都有 0 个或多个 c。小心你的正则表达式。
  • 特别是因为您将正则表达式直接传递给 Pattern 编译器。您可以轻松获得 PatternSyntaxException。
  • 不是问题,但不要为空返回 null 并使用增强的 for 循环。

标签: java regex hashmap


【解决方案1】:

您需要指定不区分大小写Pattern.compile( "c",Pattern.CASE_INSENSITIVE)。要查找带有c 的单词,您需要使用matcher.find()Matcher.matches() 尝试匹配整个字符串。

【讨论】:

  • 打败我(可能是因为我暂停链接到文档:P)。
  • 谢谢!那成功了。所以,为了直截了当:*如果我想找到所有“包含”某个正则表达式的单词,我应该使用 find() * match() 来查找所有“是”某个正则表达式的单词,仅此而已更多
【解决方案2】:

但是,嗯:

(a) 如果您打算始终按顺序搜索 HashMap,为什么要使用它?当你从不使用它们时,处理散列键和所有这些都是浪费的开销。当然,简单的 ArrayList 或 LinkedList 会更好。

(b) 这与词库有什么关系?为什么要使用正则表达式搜索词库?如果我想知道“cat”的同义词,我会认为我会搜索“cat”,而不是“c.*”。

我对如何构建同义词库的第一个想法是......好吧,我想我要问的第一个问题是,“同义词是等价关系吗?”,即如果 A 是 B 的同义词,是吗?遵循 B 是 A 的同义词吗?如果A是B的同义词,B是C的同义词,那么A是C的同义词吗?假设这些问题的答案是“是”,那么我们想要构建的是将语言中的所有单词划分为同义词集合,因此我们可以将每个集合中的任何单词映射到该集合中的所有其他单词.因此,您需要一种方法来获取任何单词,将其映射到某种联系点,然后从该联系点转到映射到它的所有单词。

这在数据库上很简单:只需创建一个包含两列的表,比如“word”和“token”,每列都有自己的索引。所有同义词都映射到同一个标记。标记可以是任何东西,只要它对于任何给定的同义词集都是唯一的,例如序列号。然后搜索给定的单词,找到相关的标记,然后获取所有带有该标记的单词。例如,我们可以使用 (big,1)、(large,1)、(gigantic,1)、(cat,2)、(feline,2) 等创建记录。搜索“big”,你会得到 1,然后搜索 1 会得到“big”、“large”和“giant”。

我不知道内置 Java 集合中的任何类可以做到这一点。我能想到的最简单的方法是构建两个协调的哈希表:一个将单词映射到标记,另一个将标记映射到单词数组。所以表 1 可能有 big->1、large->1、gigantic->1、cat->2、feline->2 等。然后表 2 映射 1->[big,large,gigantic], 2-> [cat,feline] 等。您在第一个表中查找以将单词映射到标记,并在第二个表中将该标记映射回单词列表。这很笨拙,因为所有数据都是冗余存储的,也许有更好的解决方案,但我并没有想到它。 (好吧,如果我们假设每次都按顺序搜索整个单词列表会很容易,但是随着列表变大,性能会下降。)

【讨论】:

    【解决方案3】:

    这是你使用的正则表达式吗?

    仅当整个输入序列与表达式匹配(来自 Javadoc)时,Matcher.matches() 方法才返回 true,因此在这种情况下您需要使用 "c.*",而不是 "c*" 以及匹配大小写不敏感。

    【讨论】:

    • "c*" 将是“glob”语法。
    【解决方案4】:

    正则表达式区分大小写。你想要:

    Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
    

    【讨论】:

    • 对不起,不好的例子。我已经编辑了这个问题。即使我使用适当的情况,它也不起作用。
    【解决方案5】:

    您似乎不恰当地使用了正则表达式。 "c" 只匹配小写 c,而不匹配大写。

    也就是说,我建议您考虑使用具有全文搜索功能的嵌入式数据库。

    【讨论】:

      【解决方案6】:

      回应上面“但是嗯”的杰,

      (我会添加评论,但没有代表。)

      按顺序搜索它是一种缓慢的方式。用正则表达式做这件事会陷入疯狂。用数据库做这件事是一个编程警察。当然,如果您的数据集很大,可能需要,但请记住“对于这个任务,我们被要求使用 Java 集合映射”我们应该找出使用这个 Java 集合的正确方法。

      之所以不明显是因为它不是一个集合。是两个。但这不是两张地图。它不是一个 ArrayList。缺少的是一个集合。它是同义词集的映射。

      Set 可以让你建立你的同义词列表。你可以随心所欲地制作。两组同义词就是一个很好的例子。它是 Set 而不是 ArrayList,因为您不想要重复的单词。

      Map> 将让您快速找到从任何单词到其同义词集的方式。

      打造你的套装。然后构建地图。编写一个辅助方法来构建带有地图和集合的地图。

      addSet(Map> map, Set newSet)

      此方法只是循环 newSet 并将字符串作为键添加到映射中,并将对 newSet 的引用作为值。您需要为每个集合调用一次 addSet。

      现在您已经构建了数据结构,我们应该能够找到东西。为了使它更健壮,请记住在搜索之前清理您的搜索键。使用 trim() 去除无意义的空格。使用 toLowerCase() 摆脱无意义的大写。您应该在构建集合之前(或同时)对同义词数据进行这两项操作。这样做,谁需要正则表达式?这种方式更快,更重要的是更安全。正则表达式非常强大,但是当它们出错时调试起来可能是一场噩梦。不要仅仅因为你觉得它们很酷就使用它们。

      【讨论】:

      • 使用正则表达式的意义不是因为它们“酷”。使用正则表达式的意义在于它们很难理解,所以如果你能让它工作,就证明你比那些后来阅读你的代码但无法理解它的人更聪明。 :-)
      猜你喜欢
      • 2012-01-17
      • 2015-02-16
      • 2012-08-13
      • 1970-01-01
      • 2016-12-22
      • 2017-07-15
      • 2010-09-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多