2009-05-18 65 views
13

我正在建造一個使用HashMap來存儲同義詞的詞庫。Java:在基於正則表達式的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更好的數據結構來保持像一個詞庫所需要的? (只有好奇心,因爲我們被要求使用Java Collection Map)。
  3. 還有什麼我在上面的代碼中做得不恰當嗎?

感謝, 丹

編輯:我已經糾正的例子。即使我使用正確的案例,它也不起作用。

+0

克林特有答案。但請注意,使用「c *」調用find()將匹配_any_條目 - 因爲所有條目都有0個或多個c。小心你的正則表達式。 – 2009-05-18 21:10:58

+0

尤其是因爲您將正則表達式直接傳遞給模式編譯器。你可以很容易地得到PatternSyntaxException。 – Clint 2009-05-18 21:17:10

+0

不是這個問題,但是不要爲null返回null,並使用增強for循環。 – 2009-05-18 21:29:36

回答

2

正則表達式區分大小寫。你想要:

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

對不起,不好的例子。我編輯了這個問題。即使我使用適當的情況,它也不起作用。 – Dan 2009-05-18 21:03:52

2

看起來你不適當地使用你的正則表達式。 「c」只會匹配一個小寫字母c,而不是大寫字母。

這就是說,我建議你看看使用全文搜索功能的嵌入式數據庫。

3

是你正在使用的正則表達式嗎?

只有當整個輸入序列匹配表達式(來自Javadoc)時,Matcher.matches()方法纔會返回true,所以在這種情況下您需要使用"c.*",而不是"c*"以及不區分大小寫。

10

但是,嗯:

(一)爲什麼要使用一個HashMap,如果你打算隨時搜索它順序?處理散列鍵時會浪費大量開銷,而當您從不使用散列鍵時則會浪費大量開銷。當然,一個簡單的ArrayList或LinkedList將是一個更好的主意。

(b)這與詞庫有什麼關係?爲什麼要使用正則表達式搜索同義詞庫?如果我想知道「貓」的同義詞,我會認爲我會搜索「貓」,而不是「c。*」。

我的第一個想法是如何建立一個詞庫將是...好吧,我想我要問的第一個問題是「同義詞是等價關係嗎?」,即如果A是B的同義詞,那麼它是否跟隨B是A的同義詞?如果A是B的同義詞,B是C的同義詞,那麼A是C的同義詞嗎?假設這些問題的答案是「是」,那麼我們想要構建的是將語言中的所有單詞劃分爲同義詞集合的東西,因此我們可以將每個集合中的任何單詞映射到該集合中的所有其他單詞。因此,你需要的是採取任何措辭的方式,將其映射到某種聯繫點,然後從該聯繫點轉到映射到它的所有單詞。

這對數據庫來說很簡單:只需創建一個有兩列的表格,比如說「word」和「token」,每個列都有自己的索引。所有的同義詞映射到同一個標記。令牌可以是任何東西,只要它對於任何給定的同義詞集合都是唯一的,就像序列號一樣。然後搜索給定的單詞,找到相關的標記,然後獲取具有該標記的所有單詞。例如,我們可以用(大,1),(大,1),(巨大,1),(貓,2),(貓,2)等創建記錄。搜索「大」,然後得到1,然後搜索1,你會得到「大」,「大」和「巨人」。

我不知道這樣做的內置Java集合中的任何類。我能想到的最簡單的方法是構建兩個協調散列表:一個將單詞映射爲令牌,另一個將令牌映射爲單詞數組。因此,表1可能有大 - > 1,大 - > 1,巨大 - > 1,貓 - > 2,貓 - > 2等。然後表2映射1 - > [大,大,巨大],2-> [貓,貓科動物]等。您在第一張表中查找將單詞映射到令牌,然後在第二張表中將該令牌映射回單詞列表。這是笨拙的,因爲所有的數據都是冗餘存儲的,也許有更好的解決方案,但我沒有把它從頭頂上掉下來。 (好吧,如果我們假設我們每次都會按順序搜索整個單詞列表,但是由於列表變大,性能會變差)。

0

迴應上面的「但是嗯」的Jay ,

(我想補充註釋,但沒有代表。)

順序搜索它是做什麼的緩慢方式。用正則表達式來做就是陷入瘋狂。用數據庫做這件事是一個編程警察。當然,如果你的數據集是可能需要的大量數據,但記住「對於這個任務我們被要求使用Java集合映射表」我們應該找出使用這個java集合的正確方法。

它不明顯的原因是因爲它不是一個集合。這是兩個。但它不是兩張地圖。它不是一個ArrayList。缺少的是一個集合。這是一組同義詞的映射。

設置<字符串>將讓你建立你的同義詞列表。你可以儘可能多地製作。兩套同義詞就是一個很好的例子。它不是一個ArrayList,因爲你不需要重複的單詞。

地圖<字符串,集<字符串> >將讓你快速找到你的方式從任何單詞到它的同義詞集。

建立你的設置。然後建立地圖。編寫一個幫助器方法來構建帶有地圖和集合的地圖。

addSet(地圖<字符串,請設置<字符串> >地圖,集<字符串> newSet)

這種方法只是循環newSet並添加字符串到地圖作爲鍵和值的參考newSet。你會爲每個集合調用addSet一次。

現在你已經構建了數據結構,我們應該能夠找到東西。爲了使這一點更強大,請記住在搜索之前清理搜索關鍵字。使用trim()來消除無意義的空白。使用toLowerCase()來消除無意義的大小寫。在構建集合之前(或同時),你應該在同義詞數據上完成這兩個操作。這樣做和誰需要這個正則表達式?這種方式更快,更重要的是更安全。正則表達式非常強大,但當它們出錯時可能是一個噩夢。不要僅僅因爲你認爲他們很酷就使用它們。