Range.java
Upload User: rhdiban
Upload Date: 2013-08-09
Package Size: 15085k
Code Size: 11k
Category:

Windows Develop

Development Platform:

Java

  1. /*
  2.  *    This program is free software; you can redistribute it and/or modify
  3.  *    it under the terms of the GNU General Public License as published by
  4.  *    the Free Software Foundation; either version 2 of the License, or
  5.  *    (at your option) any later version.
  6.  *
  7.  *    This program is distributed in the hope that it will be useful,
  8.  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.  *    GNU General Public License for more details.
  11.  *
  12.  *    You should have received a copy of the GNU General Public License
  13.  *    along with this program; if not, write to the Free Software
  14.  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15.  */
  16. /*
  17.  *    Range.java
  18.  *    Copyright (C) 1999 Len Trigg
  19.  *
  20.  */
  21. package weka.core;
  22. import java.io.*;
  23. import java.util.*;
  24. /** 
  25.  * Class representing a range of cardinal numbers. The range is set by a 
  26.  * string representation such as: <P>
  27.  *
  28.  * <code>
  29.  *   all
  30.  *   first-last
  31.  *   1,2,3,4
  32.  * </code> <P>
  33.  * or combinations thereof. The range is internally converted from
  34.  * 1-based to 0-based (so methods that set or get numbers not in string
  35.  * format should use 0-based numbers).
  36.  *
  37.  * @author Len Trigg (trigg@cs.waikato.ac.nz)
  38.  * @version $Revision: 1.10 $
  39.  */
  40. public class Range implements Serializable {
  41.   /** Record the string representations of the columns to delete */
  42.   Vector m_RangeStrings = new Vector();
  43.   /** Whether matching should be inverted */
  44.   boolean m_Invert;
  45.   /** The array of flags for whether an column is selected */
  46.   boolean [] m_SelectFlags;
  47.   /** Store the maximum value permitted in the range. -1 indicates that
  48.       no upper value has been set */
  49.   int m_Upper = -1;
  50.   /** Default constructor. */
  51.   public Range() {
  52.   }
  53.   /**
  54.    * Constructor to set initial range.
  55.    *
  56.    * @param rangeList the initial range
  57.    * @exception IllegalArgumentException if the range list is invalid
  58.    */
  59.   public Range(String rangeList) {
  60.     setRanges(rangeList);
  61.   }
  62.   /**
  63.    * Sets the value of "last".
  64.    *
  65.    * @param newUpper the value of "last"
  66.    */
  67.   public void setUpper(int newUpper) {
  68.     if (newUpper >= 0) {
  69.       m_Upper = newUpper;
  70.       setFlags();
  71.     }
  72.   }
  73.   
  74.   /**
  75.    * Gets whether the range sense is inverted, i.e. all <i>except</i>
  76.    * the values included by the range string are selected.
  77.    * 
  78.    * @return whether the matching sense is inverted
  79.    */
  80.   public boolean getInvert() {
  81.     return m_Invert;
  82.   }
  83.   /**
  84.    * Sets whether the range sense is inverted, i.e. all <i>except</i>
  85.    * the values included by the range string are selected.
  86.    * 
  87.    * @param newSetting true if the matching sense is inverted
  88.    */
  89.   public void setInvert(boolean newSetting) {
  90.     m_Invert = newSetting;
  91.   }
  92.   /**
  93.    * Gets the string representing the selected range of values
  94.    *
  95.    * @return the range selection string
  96.    */
  97.   public String getRanges() {
  98.     String result = null;
  99.     Enumeration enum = m_RangeStrings.elements();
  100.     while (enum.hasMoreElements()) {
  101.       if (result == null) {
  102. result = (String)enum.nextElement();
  103.       } else {
  104. result += ',' + (String)enum.nextElement();
  105.       }
  106.     }
  107.     return (result == null) ? "" : result;
  108.   }
  109.   /**
  110.    * Sets the ranges from a string representation.
  111.    *
  112.    * @param rangeList the comma separated list of ranges. The empty
  113.    * string sets the range to empty.
  114.    * @exception IllegalArgumentException if the rangeList was not well formed
  115.    */
  116.   public void setRanges(String rangeList) {
  117.     Vector ranges = new Vector (10);
  118.     // Split the rangeList up into the vector
  119.     while (!rangeList.equals("")) {
  120.       String range = rangeList.trim();
  121.       int commaLoc = rangeList.indexOf(',');
  122.       if (commaLoc != -1) {
  123. range = rangeList.substring(0, commaLoc).trim();
  124. rangeList = rangeList.substring(commaLoc + 1).trim();
  125.       } else {
  126. rangeList = "";
  127.       }
  128.       if (!range.equals("")) {
  129. if (isValidRange(range)) {
  130.   ranges.addElement(range);
  131. } else {
  132.   throw new IllegalArgumentException("Invalid range list at " + range
  133.                                              + rangeList);
  134. }
  135.       }
  136.     }
  137.     m_RangeStrings = ranges;
  138.     
  139.     if (m_Upper >= 0) {
  140.       setFlags();
  141.     }
  142.   }
  143.   /**
  144.    * Gets whether the supplied cardinal number is included in the current
  145.    * range.
  146.    *
  147.    * @param index the number of interest
  148.    * @return true if index is in the current range
  149.    * @exception RuntimeException if the upper limit of the range hasn't been defined
  150.    */
  151.   public boolean isInRange(int index) {
  152.     if (m_Upper == -1) {
  153.       throw new RuntimeException("No upper limit has been specified for range");
  154.     }
  155.     if (m_Invert) {
  156.       return !m_SelectFlags[index];
  157.     } else {
  158.       return m_SelectFlags[index];
  159.     }
  160.   }
  161.   /**
  162.    * Constructs a representation of the current range. Being a string
  163.    * representation, the numbers are based from 1.
  164.    * 
  165.    * @return the string representation of the current range
  166.    */
  167.   public String toString() {
  168.     if (m_RangeStrings.size() == 0) {
  169.       return "Empty";
  170.     }
  171.     String result ="Strings: ";
  172.     Enumeration enum = m_RangeStrings.elements();
  173.     while (enum.hasMoreElements()) {
  174.       result += (String)enum.nextElement() + " ";
  175.     }
  176.     result += "n";
  177.     result += "Invert: " + m_Invert + "n";
  178.     try {
  179.       if (m_Upper == -1) {
  180. throw new RuntimeException("Upper limit has not been specified");
  181.       }
  182.       String cols = null;
  183.       for (int i = 0; i < m_SelectFlags.length; i++) {
  184. if (isInRange(i)) {
  185.   if (cols == null) {
  186.     cols = "Cols: " + (i + 1);
  187.   } else {
  188.     cols += "," + (i + 1);
  189.   }
  190. }
  191.       }
  192.       if (cols != null) {
  193. result += cols + "n";
  194.       }
  195.     } catch (Exception ex) {
  196.       result += ex.getMessage();
  197.     }
  198.     return result;
  199.   }
  200.   /**
  201.    * Gets an array containing all the selected values, in the order
  202.    * that they were selected (or ascending order if range inversion is on)
  203.    *
  204.    * @return the array of selected values
  205.    * @exception RuntimeException if the upper limit of the range hasn't been defined
  206.    */
  207.   public int [] getSelection() {
  208.     if (m_Upper == -1) {
  209.       throw new RuntimeException("No upper limit has been specified for range");
  210.     }
  211.     int [] selectIndices = new int [m_Upper + 1];
  212.     int numSelected = 0;
  213.     if (m_Invert)
  214.     {
  215.       for (int i = 0; i <= m_Upper; i++) {
  216. if (!m_SelectFlags[i]) {
  217.   selectIndices[numSelected++] = i;
  218. }
  219.       }
  220.     }
  221.     else
  222.     {
  223.       Enumeration enum = m_RangeStrings.elements();
  224.       while (enum.hasMoreElements()) {
  225. String currentRange = (String)enum.nextElement();
  226. int start = rangeLower(currentRange);
  227. int end = rangeUpper(currentRange);
  228. for (int i = start; (i <= m_Upper) && (i <= end); i++) {
  229.   if (m_SelectFlags[i]) {
  230.     selectIndices[numSelected++] = i;
  231.   }
  232. }
  233.       }
  234.     }
  235.     int [] result = new int [numSelected];
  236.     System.arraycopy(selectIndices, 0, result, 0, numSelected);
  237.     return result;
  238.   }
  239.   /**
  240.    * Creates a string representation of the indices in the supplied array.
  241.    *
  242.    * @param indices an array containing indices to select.
  243.    * Since the array will typically come from a program, indices are assumed
  244.    * from 0, and thus will have 1 added in the String representation.
  245.    */
  246.   public static String indicesToRangeList(int []indices) {
  247.     StringBuffer rl = new StringBuffer();
  248.     int last = -2;
  249.     boolean range = false;
  250.     for(int i = 0; i < indices.length; i++) {
  251.       if (i == 0) {
  252. rl.append(indices[i] + 1);
  253.       } else if (indices[i] == last) {
  254.         range = true;
  255.       } else {
  256.         if (range) {
  257.           rl.append('-').append(last);
  258.           range = false;
  259.         }
  260. rl.append(',').append(indices[i] + 1);
  261.       }
  262.       last = indices[i] + 1;
  263.     }
  264.     if (range) {
  265.       rl.append('-').append(last);
  266.     }
  267.     return rl.toString();
  268.   }
  269.   /** Sets the flags array. */
  270.   protected void setFlags() {
  271.     m_SelectFlags = new boolean [m_Upper + 1];
  272.     Enumeration enum = m_RangeStrings.elements();
  273.     while (enum.hasMoreElements()) {
  274.       String currentRange = (String)enum.nextElement();
  275.       int start = rangeLower(currentRange);
  276.       int end = rangeUpper(currentRange);
  277.       for (int i = start; (i <= m_Upper) && (i <= end); i++) {
  278. m_SelectFlags[i] = true;
  279.       }
  280.     }
  281.   }
  282.   /**
  283.    * Translates a single string selection into it's internal 0-based equivalent
  284.    *
  285.    * @param single the string representing the selection (eg: 1 first last)
  286.    * @return the number corresponding to the selected value
  287.    */
  288.   protected int rangeSingle(String single) {
  289.     if (single.toLowerCase().equals("first")) {
  290.       return 0;
  291.     }
  292.     if (single.toLowerCase().equals("last")) {
  293.       return m_Upper;
  294.     }
  295.     int index = Integer.parseInt(single) - 1;
  296.     if (index < 0) {
  297.       index = 0;
  298.     }
  299.     if (index > m_Upper) {
  300.       index = m_Upper;
  301.     }
  302.     return index;
  303.   }
  304.   /**
  305.    * Translates a range into it's lower index.
  306.    *
  307.    * @param range the string representation of the range
  308.    * @return the lower index of the range
  309.    */
  310.   protected int rangeLower(String range) {
  311.     int hyphenIndex;
  312.     if ((hyphenIndex = range.indexOf('-')) >= 0) {
  313.       return Math.min(rangeLower(range.substring(0, hyphenIndex)),
  314.        rangeLower(range.substring(hyphenIndex + 1)));
  315.     }
  316.     return rangeSingle(range);
  317.   }
  318.   /**
  319.    * Translates a range into it's upper index. Must only be called once
  320.    * setUpper has been called.
  321.    *
  322.    * @param range the string representation of the range
  323.    * @return the upper index of the range
  324.    */
  325.   protected int rangeUpper(String range) {
  326.     int hyphenIndex;
  327.     if ((hyphenIndex = range.indexOf('-')) >= 0) {
  328.       return Math.max(rangeUpper(range.substring(0, hyphenIndex)),
  329.        rangeUpper(range.substring(hyphenIndex + 1)));
  330.     }
  331.     return rangeSingle(range);
  332.   }
  333.   /**
  334.    * Determines if a string represents a valid index or simple range.
  335.    * Examples: <code>first  last   2   first-last  first-4  4-last</code>
  336.    * Doesn't check that a < b for a-b
  337.    *
  338.    * @param range
  339.    * @return true if the range is valid
  340.    */
  341.   protected boolean isValidRange(String range) {
  342.     if (range == null) {
  343.       return false;
  344.     }
  345.     int hyphenIndex;
  346.     if ((hyphenIndex = range.indexOf('-')) >= 0) {
  347.       if (isValidRange(range.substring(0, hyphenIndex)) &&
  348.   isValidRange(range.substring(hyphenIndex + 1))) {
  349. return true;
  350.       }
  351.       return false;
  352.     }
  353.     if (range.toLowerCase().equals("first")) {
  354.       return true;
  355.     }
  356.     if (range.toLowerCase().equals("last")) {
  357.       return true;
  358.     }
  359.     try {
  360.       int index = Integer.parseInt(range);
  361.       if (index > 0) {
  362. return true;
  363.       }
  364.       return false;
  365.     } catch (NumberFormatException ex) {
  366.       return false;
  367.     }
  368.   }
  369.   /**
  370.    * Main method for testing this class.
  371.    *
  372.    * @param argv one parameter: a test range specification
  373.    */
  374.   public static void main(String [] argv) {
  375.     try {
  376.       if (argv.length == 0) {
  377. throw new Exception("Usage: Range <rangespec>");
  378.       }
  379.       Range range = new Range();
  380.       range.setRanges(argv[0]);
  381.       range.setUpper(9);
  382.       range.setInvert(false);
  383.       System.out.println("Input: " + argv[0] + "n"
  384.  + range.toString());
  385.       int [] rangeIndices = range.getSelection();
  386.       for (int i = 0; i < rangeIndices.length; i++)
  387. System.out.print(" " + (rangeIndices[i] + 1));
  388.       System.out.println("");
  389.     } catch (Exception ex) {
  390.       System.out.println(ex.getMessage());
  391.     }
  392.   }
  393. }