1 /* 2 * File: IntervalIntegerSetParser.java 3 * Created: 13.10.2006 8:52:33 4 * 5 * Copyright 2006 Michal Burda. 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 package net.sf.webmancer.util.integerset; 22 23 /** 24 * <p> 25 * This class parses string of a list of non-negative integers and creates a {@link IIntegerSet} from it. The recognized 26 * format is a list of non-negative integers delimited by colon (","), also intervals could be used. The delimiter of 27 * interval values is minus sign ("-"). Whitespaces are skipped. 28 * </p> 29 * <p> 30 * Example: <code>"-2,3,6-10,13,20-"</code> results in a {@link IIntegerSet} that contains all numbers from 31 * {@link #minimum} to 2 (inclusive), then also values 3, 6, 7, 8, 9, 10, 13 and all numbers from 20 (inclusive) to 32 * {@link #maximum}. 33 * </p> 34 * 35 * @author Michal Burda 36 */ 37 public class IntervalIntegerSetParser implements IIntegerSetParser { 38 /** 39 * The minimum value (used as a boundary for open intervals). 40 */ 41 private int minimum; 42 43 /** 44 * The maximum value (used as a boundary for open intervals). 45 */ 46 private int maximum; 47 48 /** 49 * Create new parser using given boundaries. Note that <code>minimum</code> must be lower or equal to 50 * <code>maximum</code>. 51 * 52 * @param minimum 53 * The minimum value (lower boundary for open intervals). The value must be non-negative since this 54 * parser does not support negative integers. 55 * @param maximum 56 * The maximum value (upper boundary for open intervals). A value of {@link Integer#MAX_VALUE} means 57 * "infinity". 58 */ 59 public IntervalIntegerSetParser(final int minimum, final int maximum) { 60 // TODO: check contract: minimum >= 0, maximum >= 0, minimum <= maximum 61 super(); 62 this.minimum = minimum; 63 this.maximum = maximum; 64 } 65 66 /** 67 * Create new parser using boundaries from 0 to {@link Integer#MAX_VALUE}. 68 * 69 * @see #IntervalIntegerSetParser(int, int) 70 */ 71 public IntervalIntegerSetParser() { 72 this(0, Integer.MAX_VALUE); 73 } 74 75 /** 76 * Parse the given string to integer set. 77 * 78 * @param str 79 * A string to be parsed 80 * @return An integer set corresponding to given list of integers in <code>str</code> 81 * @throws NumberFormatException 82 * if any non-integer number is found 83 * @see cz.vsb.cs.ruleminer.util.integerset.IIntegerSetParser#parse(java.lang.String) 84 */ 85 public IIntegerSet parse(final String str) throws NumberFormatException { 86 assert this.minimum >= 0; 87 assert this.maximum >= 0; 88 assert this.minimum <= this.maximum; 89 90 IntervalIntegerSet intervals = new IntervalIntegerSet(); 91 if (str != null) { 92 String[] intervalStrings = str.split(","); 93 for (String element : intervalStrings) { 94 if (element.trim().equals("")) { 95 continue; 96 } 97 String[] fromTo = element.split("-", 2); 98 assert (fromTo.length == 1 || fromTo.length == 2); 99 int from = getFrom(fromTo); 100 if (fromTo.length == 1) { 101 intervals.addInterval(from, from); 102 } else { 103 int to = getTo(fromTo); 104 if (to < from) { 105 throw new NumberFormatException("Wrong interval: " + from + " - " + to); 106 } 107 intervals.addInterval(from, to); 108 } 109 } 110 } 111 return intervals; 112 } 113 114 /** 115 * Get the left boundary of an pre-parsed interval 116 * 117 * @param fromTo 118 * @return 119 */ 120 private int getFrom(final String[] fromTo) { 121 assert (fromTo.length == 1 || fromTo.length == 2); 122 if (fromTo[0].trim().equals("")) { 123 return this.minimum; 124 } else { 125 int from = Integer.parseInt(fromTo[0].trim()); 126 checkValue(from); 127 return from; 128 } 129 } 130 131 /** 132 * @param fromTo 133 * @return 134 */ 135 private int getTo(final String[] fromTo) { 136 assert (fromTo.length == 2); 137 if (fromTo[1].trim().equals("")) { 138 return this.maximum; 139 } else { 140 int to = Integer.parseInt(fromTo[1].trim()); 141 checkValue(to); 142 return to; 143 } 144 } 145 146 /** 147 * @param value 148 * @throws NumberFormatException 149 */ 150 private void checkValue(final int value) throws NumberFormatException { 151 if (value < this.minimum) { 152 throw new NumberFormatException("Value too low: " + value + ". Minimum allowed value is: " + this.minimum); 153 } 154 if (value > this.maximum) { 155 throw new NumberFormatException("Value too high: " + value + ". Maximum allowed value is: " + this.maximum); 156 } 157 } 158 }