2013-04-11 74 views
1

我一直在使用下面的代碼嘗試從我提供的文本中提取不同的部分。你能解釋一下這個Java Regex情況的怪異行爲嗎?

它應該挑出數字,然後在[括號或"引號中包含任何部分。這是代碼。

import java.util.regex.Matcher; 
import java.util.regex.Pattern; 

public class Launcher2 { 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 
     PrintRegexes("100.000[$₮-45]"); 
    } 
    public static void PrintRegexes(String textToMatch){ 
     Pattern p = Pattern.compile("(\\[.*?\\]|\".*?\")?.*?(\\d{1,3}(?:,\\d{3})*?(?:\\.\\d+)?).*?(\\[.*?\\]|\".*?\")",Pattern.CASE_INSENSITIVE | Pattern.DOTALL); 
     Matcher m = p.matcher(textToMatch); 
     if (m.find()) 
     { 
      for(int groups =0;groups<m.groupCount();groups++){ 
       System.out.println("Group "+groups+" contains "+m.group(groups)); 
      } 
      for(int groups =0;m.find(groups);groups++){ //this will error, but right now, it's the least of my concerns 
       System.out.println("Group "+groups+" contains "+m.group(groups)); 
      } 
     } 

    } 
} 

Group 0 contains 100.000[$₮-45] 
Group 1 contains null 
Group 2 contains 100.000 
Group 3 contains [$₮-45] 
Group 0 contains 100.000[$₮-45] 
Group 1 contains null 
Group 2 contains 0.000 
Group 3 contains [$₮-45] 
Exception in thread "main" java.lang.IndexOutOfBoundsException: No group 4 //don't care about this, I've got bigger strings(fish) to regex(fry) at the moment! 
    at java.util.regex.Matcher.group(Unknown Source) 
    at Launcher2.PrintRegexes(Launcher2.java:21) 
    at Launcher2.main(Launcher2.java:10) 

所有組除了group 2一樣,一個打印出爲0.000,一個打印出的100.000

這是爲什麼?

這種行爲消失,如果我,但面前和數字後面的東西。

如果我只是把東西在前面,我得到這樣的輸出:

Group 0 contains [$₮-45]100.000 
Group 1 contains [$₮-45] 
Group 2 contains 100.000 
Group 3 contains null 
Group 0 contains [$₮-45]100.000 
Group 1 contains null 
Group 2 contains 45 
Group 3 contains null 

更加古怪!最奇怪的部分(對我來說)是,它可以在www.debuggex.com上運行。

我寫錯了嗎?還是說,當這種方法Matcher m = p.matcher(textToMatch);構建它時,匹配器不能解決羣組問題,並且這會影響它的行爲?

+0

這是一個過於複雜的正則表達式。你想在這裏做什麼?你期待什麼不同的輸入? – Keppil 2013-04-11 12:55:48

+0

@Keppil爲了便於閱讀,它被分成了更小的部分,但由於版本控制不佳,我放棄了它。它是這個組'(\ [。*?\] |「。*?」)'來獲取大括號或引號中的任何內容。然後數字。然後是之前的組。 – Pureferret 2013-04-11 12:58:22

+0

@ Gigatron我不明白我還能說些什麼。它應該收集[大括號或引號「''中包含的0-1'部分,然後可以通過該和數字之間的任何內容(具有數千個分隔符和小數位),然後可以有任何東西,然後0- 1'部分用[大括號或引號「'」括起來。可能的輸入是'[$₮-45] 100.000','100。000 [$₮-45]',''$₮-45「100,000.00','」$₮-45「10'。 – Pureferret 2013-04-11 13:06:57

回答

1

我可以在這裏看到兩個問題。

首先,您多次撥打m.find()作爲參數組,這不符合您的想法。
如果您查看JavaDoc for find(int start),您會看到它重置了匹配器,然後重新開始搜索,從輸入的指定字符開始。這解釋了在後面的迭代中匹配的較短數字序列。

其次,你需要循環,直到groups <= m.groupCount()讓所有羣體:

Pattern p = 
      Pattern.compile("(\\[.*?\\]|\".*?\")?.*?(\\d{1,3}(?:,\\d{3})*?(?:\\.\\d+)?).*?(\\[.*?\\]|\".*?\")", 
       Pattern.CASE_INSENSITIVE | Pattern.DOTALL); 
    Matcher m = p.matcher(textToMatch); 
    if (m.find()) { 
     for (int groups = 0; groups <= m.groupCount(); groups++) { 
      System.out.println("Group " + groups + " contains " + m.group(groups)); 
     } 
    } 

打印

組0包含100.000 [$₮-45]
1組包含null
集團2包含100.000
組3包含[$₮-45]

+0

我多次調用'm.find(int)',它只是返回一個布爾值,如果它發現該組,對嗎?爲什麼這不是一個有效的用途?另外你關於'<='而不是'<'的觀點是完全有效的。 – Pureferret 2013-04-11 13:10:56

+0

@ Pureferret:澄清find()調用發生了什麼。 – Keppil 2013-04-11 13:45:22

0

貌似問題是這一部分:(?:,\\d{3})*?

我想你需要((?:,\\d{3})*)?

+0

其實,只要刪除'?' – 2013-04-11 13:46:20

+0

確實,'?'是多餘的,因爲'*'不允許有一次或多次。 – Gigatron 2013-04-11 14:15:04

+1

@Keppil見Gigatron的回覆。你認爲你理解非貪婪的量詞,但你不知道。不要感到不好,大多數人不會。並不是每個正則表達式問題都可以通過在'*'中添加'?'來解決,儘管大多數人認爲是這種情況。如果你玩http://www.benhanson.net/cpp/regextl/regextl.zip,事情應該變得更清楚。順便說一句,我最喜歡的正則表達式失敗的時候,有人把'。*?'放在正則表達式的*結尾,然後奇怪它爲什麼不匹配!理由當然是,在這種情況下,最小匹配不算什麼,因此這是首選...... – 2013-04-11 15:30:27

相關問題