package edu.umd.rhsmith.diads.meater.util; /** * Represents a possibly discontinuous set of integers as a collection of <code>NumberRange</code> * objects. Allows this set to be converted to text and SQL. Capable of extracting sets from strings * such as <code>4,8-10,13-21</code> or <code>53,[8-44],[6]</code>. * * @author dmonner * */ public class NumberSet { /** * The original string source of the set, if any */ public final String from; /** * The ranges that comprise this set */ public final NumberRange[] ranges; /** * Creates a new set from a string of comma-separated ranges. * * @param from * @throws IllegalArgumentException * If any of the ranges fails to parse, or if any of the given ranges overlaps another * range */ public NumberSet(final String from) { this.from = from; // split on commas and allow the NumberRange constructor to parse each substring final String[] froms = from.split(","); this.ranges = new NumberRange[froms.length]; for(int i = 0; i < froms.length; i++) this.ranges[i] = new NumberRange(froms[i]); // check the resulting ranges for overlap with each other; there are better ways to do this, but // efficiency is not a major concern here. for(int i = 0; i < this.ranges.length; i++) for(int j = i + 1; j < this.ranges.length; j++) if(this.ranges[i].overlaps(this.ranges[j])) throw new IllegalArgumentException("Overlapping ranges: " + this.ranges[i] + " and " + this.ranges[j]); } /** * Builds a string representing the set as a SQL <code>WHERE</code> condition on the given * variable name. * * @param varname * The variable name whose range is defined by this object * @return SQL code to put in a <code>WHERE</code> condition that restricts the domain of * <code>varname</code> to the values represented by this object */ public String toSQL(final String varname) { final StringBuilder sb = new StringBuilder(); sb.append("("); sb.append(ranges[0].toSQL(varname)); sb.append(")"); for(int i = 1; i < ranges.length; i++) { sb.append(" OR "); sb.append("("); sb.append(ranges[i].toSQL(varname)); sb.append(")"); } return sb.toString(); } /** * @return This set represented as an unbracketed string */ @Override public String toString() { return toString(false); } /** * @param bracketed * Whether or not to add enclosing square brackets around each range * @return This set represented as a string */ public String toString(final boolean bracketed) { final StringBuilder sb = new StringBuilder(); sb.append(ranges[0].toString(bracketed)); for(int i = 1; i < ranges.length; i++) { sb.append(", "); sb.append(ranges[i].toString(bracketed)); } return sb.toString(); } }