2015-11-05 52 views
2

我需要將包含標準間隔符號(即(8,100),[6,10)等等)的字符串解析到Guava Range對象中。我將如何去做這些在Java中?是否有一個實用程序包可以將字符串解析爲我需要構建Guava Range對象的組件?解析間隔符號到番石榴的範圍

+0

這裏沒有這個內置的實用對象,但它看起來像用正則表達式可以相當直接地完成一些事情?你不需要一個完整的解析器;你可以提取第一個括號字符,下端點,上端點和第二個括號字符...... –

+0

謝謝 - 我在想同樣的事情,但是我對正則表達式的知識缺乏一點。我需要什麼正則表達式來提取相關的部分? – Dave221

回答

2

如果我們看一下模式,無論是與一個'[''('開始的時間間隔,則隨後在至少一個數字,後跟一個逗號,再一個或多個數字和任何']'')'完成。

因此正則表達式看起來像這樣:

^[\\(|\\[](\\d+),(\\d+)[\\)|\\]]$ 

這被分解:

^ 
[\\(|\\[] -> start either with `'['` or `'('` (we need to escape the special characters with `\\`) 
(\\d+) -> followed by one or more digit that we capture in a group 
, -> followed by a comma 
(\\d+) -> followed again by one or more digit that we capture in another group 
[\\)|\\]] -> and that finishes either with `']'` or `')'` 
$ 

^$斷言,所有的字符串匹配的表達式,而不只是它的一部分。

所以我們有正則表達式,耶!

現在我們需要從它創建一個Pattern實例,以便能夠從中獲取匹配器。最後,我們檢查字符串相匹配,我們抓住相應的組

Pattern p = Pattern.compile("^[\\(|\\[](\\d+),(\\d+)[\\)|\\]]$"); 
Matcher m = p.matcher("(0,100)"); 

if(matcher.matches()) { 
    int lowerBound = Integer.parseInt(matcher.group(1)); 
    int upperBound = Integer.parseInt(matcher.group(2)); 
    System.out.println(lowerBound + "_" + upperBound); 
} 

下輸出0_100

現在最後一步,獲取第一個和最後一個字符並從中創建適當的範圍;把他們放在一起:

class RangeFactory { 

    private static final Pattern p = Pattern.compile("^[\\(|\\[](\\d+),(\\d+)[\\)|\\]]$"); 

    public static Range from(String range) { 
     Matcher m = p.matcher(range); 
     if(m.matches()) { 
      int length = range.length(); 

      int lowerBound = Integer.parseInt(m.group(1)); 
      int upperBound = Integer.parseInt(m.group(2)); 

      if(range.charAt(0) == '(') { 
       if(range.charAt(length - 1) == ')') { 
        return Range.open(lowerBound, upperBound); 
       } 
       return Range.openClosed(lowerBound, upperBound); 
      } else { 
       if(range.charAt(length - 1) == ')') { 
        return Range.closedOpen(lowerBound, upperBound); 
       } 
       return Range.closed(lowerBound, upperBound); 
      } 
     } 
     throw new IllegalArgumentException("Range " + range + " is not valid."); 
    } 
} 

下面是一些測試用例:

List<String> ranges = 
    Arrays.asList("(0,100)", "[0,100]", "[0,100)", "(0,100]", "", "()", "(0,100", "[,100]", "[100]"); 

for(String range : ranges) { 
    try { 
     System.out.println(RangeFactory.from(range)); 
    } catch (IllegalArgumentException ex) { 
     System.out.println(ex); 
    } 
} 

,輸出:

(0‥100) 
[0‥100] 
[0‥100) 
(0‥100] 
java.lang.IllegalArgumentException: Range is not valid. 
java.lang.IllegalArgumentException: Range() is not valid. 
java.lang.IllegalArgumentException: Range (0,100 is not valid. 
java.lang.IllegalArgumentException: Range [,100] is not valid. 
java.lang.IllegalArgumentException: Range [100] is not valid. 

可以改善正則表達式(接受的範圍與無限邊界等) ,但它應該給你一個很好的起點。

希望它有幫助! :)

0

也有類似的問題,這種解決方案提出了:

private static final Pattern INTERVAL_PATTERN = Pattern.compile("([\\[\\(])(-?∞?\\d*)(?:\\,|\\.\\.)(-?∞?\\d*)([\\]\\)])"); 

/** 
* Parses integer ranges of format (2,5], (2..5], (2,), [2..), [2..∞), [2,∞) 
* 
* @param notaiton The range notation to parse 
* @throws IllegalArgumentException if the interval is not in the defined notation format. 
*/ 
public static Range<Integer> parseIntRange(@NonNull String notaiton) { 
    Matcher matcher = INTERVAL_PATTERN.matcher(notaiton); 
    if (matcher.matches()) { 

     Integer lowerBoundEndpoint = Ints.tryParse(matcher.group(2)); 
     Integer upperBoundEndpoint = Ints.tryParse(matcher.group(3)); 
     if (lowerBoundEndpoint == null && upperBoundEndpoint == null) { 
      return Range.all(); 
     } 
     boolean lowerBoundInclusive = matcher.group(1).equals("["); 
     boolean upperBoundInclusive = matcher.group(4).equals("]"); 

     //lower infinity case 
     if (lowerBoundEndpoint == null) { 
      if (upperBoundInclusive) { 
       return Range.atMost(upperBoundEndpoint); 
      } else { 
       return Range.lessThan(upperBoundEndpoint); 
      } 
     } //upper infinity case 
     else if (upperBoundEndpoint == null) { 
      if (lowerBoundInclusive) { 
       return Range.atLeast(lowerBoundEndpoint); 
      } else { 
       return Range.greaterThan(lowerBoundEndpoint); 
      } 
     } 

     //non infinity cases 
     if (lowerBoundInclusive) { 
      if (upperBoundInclusive) { 
       return Range.closed(lowerBoundEndpoint, upperBoundEndpoint); 
      } else { 
       return Range.closedOpen(lowerBoundEndpoint, upperBoundEndpoint); 
      } 

     } else { 
      if (upperBoundInclusive) { 
       return Range.openClosed(lowerBoundEndpoint, upperBoundEndpoint); 
      } else { 
       return Range.open(lowerBoundEndpoint, upperBoundEndpoint); 
      } 
     } 
    } else { 
     throw new IllegalArgumentException(notaiton + " is not a valid range notation"); 
    } 
} 

單元測試:

@Test 
public void testParseIntRange_infinites_parsesOK() { 
    assertThat(NumberUtils.parseIntRange("(,2)"), is(Range.lessThan(2))); 
    assertThat(NumberUtils.parseIntRange("(2,)"), is(Range.greaterThan(2))); 
    assertThat(NumberUtils.parseIntRange("(,2]"), is(Range.atMost(2))); 
    assertThat(NumberUtils.parseIntRange("[2,)"), is(Range.atLeast(2))); 
    assertThat(NumberUtils.parseIntRange("(..2)"), is(Range.lessThan(2))); 
    assertThat(NumberUtils.parseIntRange("(2..)"), is(Range.greaterThan(2))); 
    assertThat(NumberUtils.parseIntRange("(..2]"), is(Range.atMost(2))); 
    assertThat(NumberUtils.parseIntRange("[2..)"), is(Range.atLeast(2))); 

    assertThat(NumberUtils.parseIntRange("(∞,2)"), is(Range.lessThan(2))); 
    assertThat(NumberUtils.parseIntRange("(2,∞)"), is(Range.greaterThan(2))); 
    assertThat(NumberUtils.parseIntRange("(∞,2]"), is(Range.atMost(2))); 
    assertThat(NumberUtils.parseIntRange("[2,∞)"), is(Range.atLeast(2))); 
    assertThat(NumberUtils.parseIntRange("(∞..2)"), is(Range.lessThan(2))); 
    assertThat(NumberUtils.parseIntRange("(2..∞)"), is(Range.greaterThan(2))); 
    assertThat(NumberUtils.parseIntRange("(∞..2]"), is(Range.atMost(2))); 
    assertThat(NumberUtils.parseIntRange("[2..∞)"), is(Range.atLeast(2))); 

    assertThat(NumberUtils.parseIntRange("(-∞,2)"), is(Range.lessThan(2))); 
    assertThat(NumberUtils.parseIntRange("(-∞,2]"), is(Range.atMost(2))); 
    assertThat(NumberUtils.parseIntRange("(-∞,]"), is(Range.all())); 
} 

@Test 
public void testParseIntRange_parsesOK() { 
    assertThat(NumberUtils.parseIntRange("(-2,3)"), is(Range.open(-2, 3))); 
    assertThat(NumberUtils.parseIntRange("(-2,-1)"), is(Range.open(-2, -1))); 
    assertThat(NumberUtils.parseIntRange("(2,3)"), is(Range.open(2, 3))); 
    assertThat(NumberUtils.parseIntRange("[2,3)"), is(Range.closedOpen(2, 3))); 
    assertThat(NumberUtils.parseIntRange("(2,3]"), is(Range.openClosed(2, 3))); 
    assertThat(NumberUtils.parseIntRange("[2,3]"), is(Range.closed(2, 3))); 

    assertThat(NumberUtils.parseIntRange("(2..3)"), is(Range.open(2, 3))); 
    assertThat(NumberUtils.parseIntRange("[2..3)"), is(Range.closedOpen(2, 3))); 
    assertThat(NumberUtils.parseIntRange("(2..3]"), is(Range.openClosed(2, 3))); 
    assertThat(NumberUtils.parseIntRange("[2..3]"), is(Range.closed(2, 3))); 
} 

@Test 
public void testParseIntRange_WithInvalidStrings_failsAccordingly() { 
    String[] invalidParams = { 
     null, "", "(4 5", "[2,3] ", " [2,3]", "[2,3][2,3]", "[a,b]", " [2..3]", "[2.3]", 
     "[3...4]", "(3 4)", "[2]", "(5,1)", "ab[2,4]", "[2,4]cd", "(2,-2)", "(2,2)" 
    }; 
    for (String invalidParam : invalidParams) { 
     try { 
      NumberUtils.parseIntRange(invalidParam); 
      fail("Parsing '" + invalidParam + "' did not fail"); 
     } catch (IllegalArgumentException ex) { 
     } 
    } 
}