14

我正在使用 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;
    }
}

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

cat, car, chopper

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

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

谢谢,丹

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

4

6 回答 6

10

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

于 2009-05-18T21:04:53.390 回答
9

但是,嗯:

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

(乙)这与词库有什么关系?为什么要使用正则表达式搜索词库?如果我想知道“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] 等。您在第一个表中查找以将单词映射到标记,并在第二个表中将该标记映射回单词列表。这很笨拙,因为所有数据都是冗余存储的,也许有更好的解决方案,但我并没有想到它。(好吧,如果我们假设每次都按顺序搜索整个单词列表会很容易,但是随着列表变大,性能会变差。)

于 2009-05-18T22:09:27.910 回答
3

那是您正在使用的正则表达式吗?

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

于 2009-05-18T21:17:45.707 回答
2

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

Pattern p = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
于 2009-05-18T21:00:10.310 回答
2

看起来你不恰当地使用你的正则表达式。"c" 只匹配小写 c,而不匹配大写。

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

于 2009-05-18T21:03:28.650 回答
0

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

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

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

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

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

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

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

addSet(Map<String, Set<String>> map, Set<String> newSet)

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

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

于 2013-09-14T12:10:29.333 回答