2016-06-10 55 views
0

我有一個包含名字和姓氏的字符串列表,我有一個自由文本。Java正則表達式在文本中查找所有可能的列表對

List<String> names; // contains: "jon", "snow", "arya", "stark", ... 
String text = "jon snow and stark arya"; 

我一定要找到所有的名字和姓氏,可能與Java正則表達式(因此使用Pattern和Matcher對象)。所以,我想是這樣的:

List<String> foundNames; // contains: "jon snow", "stark arya" 

我已經這樣做了2種可能的方式,但不使用正則表達式,它們不是靜態的東陽有一個包含所有名稱的列表「名稱」一類的NameFinder的一部分。

public List<String> findNamePairs(String text) { 
    List<String> foundNamePairs = new ArrayList<String>(); 
    List<String> names = this.names; 
    text = text.toLowerCase(); 

    for (String name : names) { 
     String nameToSearch = name + " "; 
     int index = text.indexOf(nameToSearch); 
     if (index != -1) { 
      String textSubstring = text.substring(index + nameToSearch.length()); 
      for (String nameInner : names) { 
       if (name != nameInner && textSubstring.startsWith(nameInner)) { 
        foundNamePairs.add(name + " " + nameInner); 
       } 
      } 
     } 
    } 

    removeDuplicateFromList(foundNamePairs); 

    return foundNamePairs; 
} 

或更壞的(非常糟糕)的方式(創建所有可能的對):

public List<String> findNamePairsInTextNotOpt(String text) { 
    List<String> foundNamePairs = new ArrayList<String>(); 
    text = text.toLowerCase(); 
    List<String> pairs = getNamePairs(this.names); 

    for (String name : pairs) { 
     if (text.contains(name)) { 
      foundNamePairs.add(name); 
     } 
    } 

    removeDuplicateFromList(foundNamePairs); 

    return foundNamePairs; 
} 
+1

究竟是什麼問題? –

+0

你爲什麼要用正則表達式來做到這一點? – explv

+0

@JohnBellinger,我會盡力解釋一下。但是,我需要在Java正則表達式的「正常」方法中做我所做的。 –

回答

0

您可以使用名稱的列表中的正則表達式,然後使用發現找到的名字。爲確保您沒有重複,可以檢查名稱是否已經在發現名稱列表中。代碼看起來像這樣。

List<String> names = Arrays.asList("jon", "snow", "stark", "arya"); 
String text = "jon snow and Stark arya and again Jon Snow"; 

StringBuilder regexBuilder = new StringBuilder(); 

for (int i = 0; i < names.size(); i += 2) { 
    regexBuilder.append("(") 
     .append(names.get(i)) 
     .append(" ") 
     .append(names.get(i + 1)) 
     .append(")"); 
    if (i != names.size() - 2) regexBuilder.append("|"); 
} 

System.out.println(regexBuilder.toString()); 

Pattern compile = Pattern.compile(regexBuilder.toString(), Pattern.CASE_INSENSITIVE); 

Matcher matcher = compile.matcher(text); 

List<String> found = new ArrayList<>(); 

int start = 0; 
while (matcher.find(start)) { 
    String match = matcher.group().toLowerCase(); 

    if (!found.contains(match)) found.add(match); 
    start = matcher.end(); 
} 

for (String s : found) System.out.println("found: " + s); 

如果您想區分大小寫,只需在Pattern.compile()中刪除該標誌即可。如果所有匹配都具有相同的大小寫,則可以省略while循環中的toLowerCase()

但是請確保列表包含2的倍數作爲列表元素(名稱和姓氏),否則for循環將拋出IndexOutOfBoundsException。此外,該命令在我的代碼中很重要。它只會按照它們在列表中出現的順序找到名稱對。如果你想要兩個訂單,你可以相應地改變正則表達式的產生。

編輯:由於不知名字是姓氏還是名字以及哪個名字/姓氏對構成,正則表達式的生成必須以不同的方式完成。

StringBuilder regexBuilder = new StringBuilder("("); 

for (int i = 0; i < names.size(); i++) { 
    regexBuilder.append("(") 
      .append(names.get(i)) 
      .append(")"); 
    if (i != names.size() - 1) regexBuilder.append("|"); 
} 

regexBuilder.append(") "); 
regexBuilder.append(regexBuilder); 
regexBuilder.setLength(regexBuilder.length() - 1); 


System.out.println(regexBuilder.toString()); 

這個正則表達式會匹配任何給定的名字後跟一個空格,然後再匹配任何名字。

+0

感謝你的幫助,我沒有詳細說明,在我的名單中,我的名字和姓氏是混合的。 所以列表可以是: 列表 names = Arrays.asList(「name1」,「name2」,「surname2」,「surname1」); 所以我不能把正則表達式(element1 element2) (element3 element4),我必須把所有可能的組合,我恐怕它可能會很慢。 –

+0

那麼你必須測試所有的組合,因爲你沒有關於哪個名字和姓氏在一起的信息,以及不知道名稱是姓名還是姓氏。我將在關於爲此生成正則表達式的答案中添加一節。 – Leon

相關問題