2012-10-25 16 views
4

這很奇怪,因爲它是非常簡單的dd/mm格式的正則表達式。結果應該是:"Group 1: 14; Group 2: 12",但它是"Group 1: 14; Group 2: 1"正則表達式的日期省略了一個月份的字符

第二組只捕獲第一個字符,但省略第二個字符(示例中的'2')。

String sDay = "(?:0?[1-9]|[12][0-9]|3[01])"; 
String sMonth = "(?:0?[1-9]|1[0-2])"; 
String sDot = "[\\.]"; 
String sSlash = "[/]"; 
String sMinus = "[\\-]"; 
String sSeparators = (sDot + "|" + sSlash + "|" + sMinus); 

Pattern reDayMonth = 
    Pattern.compile("(" + sDay + ")" + "(?:" + sSeparators + ")" + "(" + sMonth+ ")"); 

String s = "14/12"; 
Matcher reMatcher = reDayMonth.matcher(s); 
boolean found = reMatcher.find(); 

System.out.println("Group 1: " + reMatcher.group(1) + "; Group 2: " + reMatcher.group(2)); 

我不明白爲什麼。你可以幫我嗎?

+0

當多個替代方案可以匹配時,首先放置最長的替代方案。 – ridgerunner

回答

3

在你的月份正則表達式中,你允許一個數字首先匹配,所以它(然後停止)。嘗試移動所需要的,兩位數的月份檢查第一和然後個位數:

(?:0?[1-9]|1[0-2]) 

應該變成:

(?:1[0-2]|0?[1-9]) 

UPDATE(推理)
之所以相同模式,以0?開頭,在day模式下工作,但不在month模式中,因爲您指定有必須遵循的字符模式 - 因此,處理day的整個模式。然而,在month模式中,沒有指定要跟隨的字符;因此,它在找到第一場比賽時停下來,這場比賽在原始模式中是一位數字。

如果你扭轉輸入格式(即不是dd/mm您使用mm/dd),並簡單地交換在編譯的正則表達式sDaysMonth,你會真正注意到month會正確地匹配兩個號碼和day會失敗代替!

解決此問題的一種方法是先匹配兩個字符的規則,然後然後可選的單個字符,就像我的回答所暗示的那樣。另一種方法是假定/要求你的輸入日期本身就在一行上(即日期從行首開始並在行尾結束而沒有其他文本)。如果這是真的,你可以使用正則表達式的^$字符分別匹配了該行的開頭和結尾,:

Pattern.compile("^(" + sDay + ")" + "(?:" + sSeparators + ")" + "(" + sMonth+ ")$"); 

這樣做,將徹底評估每個模式來查找全場比賽,在這情況下,你應該始終匹配正確的月份/日期。

本網注由@MarkoTopolnik(建議,不回答特定雖然)
每一個有用的意見/建議,你不需要使用非捕獲組,每組左右(月+日)特別是因爲您立即將它們包裝在捕獲組中,使得非捕獲組無用。所以,上述模式可以簡單地變爲:

1[0-2]|0?[1-9] 
+0

在捕獲組部門中這不會失敗嗎?實際上,我認爲非捕獲組夥伴是多餘的。 –

+1

OP我應該刪除非捕獲組夥伴。一切都會保持不變。 –

+0

「試着移動所需的兩位數的月份先檢查一下,然後再輸入單個數字:(?:1 [0-2] | 0?[1-9])」 - >非常感謝newfurniturey。這纔是重點!!! – Trang