Java:基于正则表达式在HashMap密钥中搜索?

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

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

public ArrayList searchDefinition(String regex) { ArrayList results = new ArrayList(); Pattern p = Pattern.compile(regex); Set keys = thesaurus.keySet(); Iterator 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. 还有其他我在上面的代码中做得不合适吗?

谢谢,丹

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

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

但是,嗯:

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

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

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

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

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

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

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

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

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

看起来你正在使用你的正则表达式。 “c”只匹配小写字母c,而不是大写字母。

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

回应杰伊的“但是嗯”,

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

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

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

Set 将允许您构建同义词列表。 你可以随心所欲地制作多少。 两组同义词就是一个很好的例子。 这是一个Set not a ArrayList,因为你不想要重复的单词。

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

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

addSet(Map > map,Set newSet)

此方法只是循环newSet并将字符串作为键添加到地图,并将newSet的引用添加为值。 你可以为每一组调用addSet一次。

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