2015-11-05 56 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) { 
     } 
    } 
}