content: /*
   *    This program is free software; you can redistribute it and/or modify
   *    it under the terms of the GNU General Public License as published by
   *    the Free Software Foundation; either version 2 of the License, or
   *    (at your option) any later version.
   *
   *    This program is distributed in the hope that it will be useful,
   *    but WITHOUT ANY WARRANTY; without even the implied warranty of
   *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *    GNU General Public License for more details.
   *
   *    You should have received a copy of the GNU General Public License
   *    along with this program; if not, write to the Free Software
   *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   */
  
  /*
   * RemoveByName.java
   * Copyright (C) 2009 University of Waikato, Hamilton, New Zealand
   *
   */
  
  package weka.filters.unsupervised.attribute;
  
  import java.util.Enumeration;
  import java.util.Vector;
  
  import weka.core.Capabilities;
  import weka.core.Instance;
  import weka.core.Instances;
  import weka.core.Option;
  import weka.core.RevisionUtils;
  import weka.core.Utils;
  import weka.filters.SimpleStreamFilter;
  
  /** 
   <!-- globalinfo-start -->
   * Removes attributes based on a regular expression matched against their names.
   * <p/>
   <!-- globalinfo-end -->
   *
   <!-- options-start -->
   * Valid options are: <p/>
   * 
   * <pre> -D
   *  Turns on output of debugging information.</pre>
   * 
   * <pre> -E &lt;regular expression&gt;
   *  The regular expression to match the attribute names against.
   *  (default: ^.*id$)</pre>
   * 
   * <pre> -V
   *  Flag for inverting the matching sense. If set, attributes are kept
   *  instead of deleted.
   *  (default: off)</pre>
   * 
   <!-- options-end -->
   *
   * @author FracPete (fracpete at waikato dot ac dot nz)
   * @version $Revision: 6076 $
   */
  public class RemoveByName
    extends SimpleStreamFilter {
  
    /** for serialization. */
    private static final long serialVersionUID = -3335106965521265631L;
  
    /** the default expression. */
    public final static String DEFAULT_EXPRESSION = "^.*id$";
    
    /** the regular expression for selecting the attributes by name. */
    protected String m_Expression = DEFAULT_EXPRESSION;
    
    /** whether to invert the matching sense. */
    protected boolean m_InvertSelection;
  
    /** the Remove filter used internally for removing the attributes. */
    protected Remove m_Remove;
    
    /**
     * Returns a string describing this classifier.
     *
     * @return      a description of the classifier suitable for
     *              displaying in the explorer/experimenter gui
     */
    public String globalInfo() {
      return 
          "Removes attributes based on a regular expression matched against "
        + "their names.";
    }
  
    /**
     * Gets an enumeration describing the available options.
     *
     * @return an enumeration of all the available options.
     */
    public Enumeration listOptions() {
      Vector	result;
      Enumeration	enm;
  
      result = new Vector();
  
      enm = super.listOptions();
      while (enm.hasMoreElements())
        result.addElement(enm.nextElement());
  
      result.addElement(new Option(
  	"\tThe regular expression to match the attribute names against.\n"
  	+ "\t(default: " + DEFAULT_EXPRESSION + ")",
  	"E", 1, "-E <regular expression>"));
  
      result.addElement(new Option(
  	"\tFlag for inverting the matching sense. If set, attributes are kept\n"
  	+ "\tinstead of deleted.\n"
  	+ "\t(default: off)",
  	"V", 0, "-V"));
  
      return result.elements();
    }
  
    /**
     * returns the options of the current setup.
     *
     * @return      the current options
     */
    public String[] getOptions() {
      int       		i;
      Vector<String>	result;
      String[]		options;
  
      result = new Vector();
      options = super.getOptions();
      for (i = 0; i < options.length; i++)
        result.add(options[i]);
  
      result.add("-E");
      result.add("" + getExpression());
  
      if (getInvertSelection())
        result.add("-V");
  
      return (String[]) result.toArray(new String[result.size()]);	  
    }
  
    /**
     * Parses the options for this object. <p/>
     *
     <!-- options-start -->
     * Valid options are: <p/>
     * 
     * <pre> -D
     *  Turns on output of debugging information.</pre>
     * 
     * <pre> -E &lt;regular expression&gt;
     *  The regular expression to match the attribute names against.
     *  (default: ^.*id$)</pre>
     * 
     * <pre> -V
     *  Flag for inverting the matching sense. If set, attributes are kept
     *  instead of deleted.
     *  (default: off)</pre>
     * 
     <!-- options-end -->
     *
     * @param options	the options to use
     * @throws Exception	if the option setting fails
     */
    public void setOptions(String[] options) throws Exception {
      String	tmpStr;
  
      super.setOptions(options);
  
      tmpStr = Utils.getOption("E", options);
      if (tmpStr.length() != 0)
        setExpression(tmpStr);
      else
        setExpression(DEFAULT_EXPRESSION);
  
      setInvertSelection(Utils.getFlag("V", options));
    }
  
    /**
     * Sets the regular expression to match the attribute names against.
     *
     * @param value 	the regular expression
     */
    public void setExpression(String value) {
      m_Expression = value;
    }
  
    /**
     * Returns the regular expression in use.
     *
     * @return 		the regular expression
     */
    public String getExpression() {
      return m_Expression;
    }
  
    /**
     * Returns the tip text for this property.
     *
     * @return 		tip text for this property suitable for
     * 			displaying in the explorer/experimenter gui
     */
    public String expressionTipText() {
      return "The regular expression to match the attribute names against.";
    }
  
    /**
     * Set whether selected columns should be removed or kept. If true the 
     * selected columns are kept and unselected columns are deleted. If false
     * selected columns are deleted and unselected columns are kept.
     *
     * @param value 	the new invert setting
     */
    public void setInvertSelection(boolean value) {
      m_InvertSelection = value;
    }
  
    /**
     * Get whether the supplied columns are to be removed or kept.
     *
     * @return 		true if the supplied columns will be kept
     */
    public boolean getInvertSelection() {
      return m_InvertSelection;
    }
  
    /**
     * Returns the tip text for this property.
     *
     * @return 		tip text for this property suitable for
     * 			displaying in the explorer/experimenter gui
     */
    public String invertSelectionTipText() {
      return "Determines whether action is to select or delete."
        + " If set to true, only the specified attributes will be kept;"
        + " If set to false, specified attributes will be deleted.";
    }
    
    /**
     * Determines the output format based on the input format and returns 
     * this. In case the output format cannot be returned immediately, i.e.,
     * immediateOutputFormat() returns false, then this method will be called
     * from batchFinished().
     *
     * @param inputFormat	the input format to base the output format on
     * @return		the output format
     * @throws Exception	in case the determination goes wrong
     */
    protected Instances determineOutputFormat(Instances inputFormat) throws Exception {
      Vector<Integer>	indices;
      int[]		attributes;
      int			i;
      
      // determine indices
      indices = new Vector<Integer>();
      for (i = 0; i < inputFormat.numAttributes(); i++) {
        // skip class
        if (i == inputFormat.classIndex())
  	continue;
        if (inputFormat.attribute(i).name().matches(m_Expression))
  	indices.add(i);
      }
      attributes = new int[indices.size()];
      for (i = 0; i < indices.size(); i++)
        attributes[i] = indices.get(i);
      
      m_Remove = new Remove();
      m_Remove.setAttributeIndicesArray(attributes);
      m_Remove.setInvertSelection(getInvertSelection());
      m_Remove.setInputFormat(inputFormat);
      
      return m_Remove.getOutputFormat();
    }
  
    /** 
     * Returns the Capabilities of this filter.
     *
     * @return            the capabilities of this object
     * @see               Capabilities
     */
    public Capabilities getCapabilities() {
      Capabilities result;
      
      result = new Remove().getCapabilities();
      result.setOwner(this);
      
      return result;
    }
    
    /**
     * processes the given instance (may change the provided instance) and
     * returns the modified version.
     *
     * @param instance    the instance to process
     * @return            the modified data
     * @throws Exception  in case the processing goes wrong
     */
    protected Instance process(Instance instance) throws Exception {
      m_Remove.input(instance);
      return m_Remove.output();
    }
    
    /**
     * Returns the revision string.
     * 
     * @return		the revision
     */
    public String getRevision() {
      return RevisionUtils.extract("$Revision: 6076 $");
    }
  
    /**
     * runs the filter with the given arguments.
     *
     * @param args      the commandline arguments
     */
    public static void main(String[] args) {
      runFilter(new RemoveByName(), args);
    }
  }
  