Addition of GreaterThan and LessThan in formulas (IF Functions)

Originally submitted by Cameron Riley (PR 16392). Thanks.
Added simple tests at high and low level, more complicated cases to be tested
<= and >= probably still wont work!
Had to apply diff by hand, one horrible line at a time (yikes!!)


git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@353081 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Avik Sengupta 2003-05-04 18:22:09 +00:00
parent 4d078576d6
commit b59b8abe8e
6 changed files with 490 additions and 79 deletions

View File

@ -61,27 +61,9 @@ import java.util.Iterator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import org.apache.poi.hssf.record.formula.AbstractFunctionPtg; //import PTG's .. since we need everything, import *
import org.apache.poi.hssf.record.formula.AddPtg; import org.apache.poi.hssf.record.formula.*;
import org.apache.poi.hssf.record.formula.Area3DPtg;
import org.apache.poi.hssf.record.formula.AreaPtg;
import org.apache.poi.hssf.record.formula.AttrPtg;
import org.apache.poi.hssf.record.formula.BoolPtg;
import org.apache.poi.hssf.record.formula.ConcatPtg;
import org.apache.poi.hssf.record.formula.DividePtg;
import org.apache.poi.hssf.record.formula.EqualPtg;
import org.apache.poi.hssf.record.formula.FuncVarPtg;
import org.apache.poi.hssf.record.formula.IntPtg;
import org.apache.poi.hssf.record.formula.MultiplyPtg;
import org.apache.poi.hssf.record.formula.NumberPtg;
import org.apache.poi.hssf.record.formula.OperationPtg;
import org.apache.poi.hssf.record.formula.ParenthesisPtg;
import org.apache.poi.hssf.record.formula.PowerPtg;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.Ref3DPtg;
import org.apache.poi.hssf.record.formula.ReferencePtg;
import org.apache.poi.hssf.record.formula.StringPtg;
import org.apache.poi.hssf.record.formula.SubtractPtg;
import org.apache.poi.hssf.util.SheetReferences; import org.apache.poi.hssf.util.SheetReferences;
@ -98,6 +80,7 @@ import org.apache.poi.hssf.util.SheetReferences;
* @author Avik Sengupta <avik AT Avik Sengupta DOT com> * @author Avik Sengupta <avik AT Avik Sengupta DOT com>
* @author Andrew C. oliver (acoliver at apache dot org) * @author Andrew C. oliver (acoliver at apache dot org)
* @author Eric Ladner (eladner at goldinc dot com) * @author Eric Ladner (eladner at goldinc dot com)
* @author Cameron Riley (criley at ekmail.com)
*/ */
public class FormulaParser { public class FormulaParser {
@ -154,7 +137,7 @@ public class FormulaParser {
return; return;
} }
look=formulaString.charAt(pointer++); look=formulaString.charAt(pointer++);
//System.out.println("Got char: "+Look); //System.out.println("Got char: "+ look);
} }
@ -391,7 +374,6 @@ public class FormulaParser {
return count; return count;
} }
/** /**
* Generates the variable function ptg for the formula. * Generates the variable function ptg for the formula.
* <p> * <p>
@ -543,13 +525,16 @@ public class FormulaParser {
/** Parse and Translate a Math Term */ /** Parse and Translate a Math Term */
private void Term(){ private void Term(){
Factor(); Factor();
while (look == '*' || look == '/' || look == '^' || look == '&' || look == '=' ) { while (look == '*' || look == '/' || look == '^' || look == '&' ||
look == '=' || look == '>' || look == '<' ) {
///TODO do we need to do anything here?? ///TODO do we need to do anything here??
if (look == '*') Multiply(); if (look == '*') Multiply();
if (look == '/') Divide(); if (look == '/') Divide();
if (look == '^') Power(); if (look == '^') Power();
if (look == '&') Concat(); if (look == '&') Concat();
if (look == '=') Equal(); if (look == '=') Equal();
if (look == '>') GreaterThan();
if (look == '<') LessThan();
} }
} }
@ -600,11 +585,27 @@ public class FormulaParser {
if (look == '-') Subtract(); if (look == '-') Subtract();
if (look == '*') Multiply(); if (look == '*') Multiply();
if (look == '/') Divide(); if (look == '/') Divide();
if (look == '>') GreaterThan();
if (look == '<') LessThan();
} }
addArgumentPointer(); addArgumentPointer();
} }
/** Recognize and Translate a Greater Than */
private void GreaterThan() {
Match('>');
Term();
tokens.add(new GreaterThanPtg());
}
/** Recognize and Translate a Less Than */
private void LessThan() {
Match('<');
Term();
tokens.add(new LessThanPtg());
}
//{--------------------------------------------------------------} //{--------------------------------------------------------------}
//{ Parse and Translate an Assignment Statement } //{ Parse and Translate an Assignment Statement }
@ -826,7 +827,8 @@ end;
* Useful for testing * Useful for testing
*/ */
public String toString() { public String toString() {
SheetReferences refs = book.getSheetReferences(); SheetReferences refs = null;
if (book!=null) book.getSheetReferences();
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
for (int i=0;i<tokens.size();i++) { for (int i=0;i<tokens.size();i++) {
buf.append( ( (Ptg)tokens.get(i)).toFormulaString(refs)); buf.append( ( (Ptg)tokens.get(i)).toFormulaString(refs));

View File

@ -0,0 +1,175 @@
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache POI" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* "Apache POI", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
/*
* GreaterThanPtg.java
*
* Created on January 23, 2003, 9:47 AM
*/
package org.apache.poi.hssf.record.formula;
import java.util.List;
import org.apache.poi.hssf.util.SheetReferences;
/**
* Greater than operator PTG ">"
* @author Cameron Riley (criley at ekmail.com)
*/
public class GreaterThanPtg
extends OperationPtg
{
public final static int SIZE = 1;
public final static byte sid = 0x0D;
private final static String GREATERTHAN = ">";
/**
* Constructor. Creates new GreaterThanPtg
*/
public GreaterThanPtg()
{
//deliberately empty
}
/**
* Constructor. Create a new GreaterThanPtg.
* @param data the byte array to have the PTG added to
* @param offset the offset to the PTG to.
*/
public GreaterThanPtg(byte [] data, int offset)
{
//deliberately empty
}
/**
* Write the sid to an array
* @param array the array of bytes to write the sid to
* @param offset the offset to add the sid to
*/
public void writeBytes(byte [] array, int offset)
{
array[ offset + 0 ] = sid;
}
/**
* Get the size of the sid
* @return int the size of the sid in terms of byte additions to an array
*/
public int getSize()
{
return SIZE;
}
/**
* Get the type of PTG for Greater Than
* @return int the identifier for the type
*/
public int getType()
{
return TYPE_BINARY;
}
/**
* Get the number of operands for the Less than operator
* @return int the number of operands
*/
public int getNumberOfOperands()
{
return 2;
}
/**
* Implementation of method from Ptg
* @param refs the Sheet References
*/
public String toFormulaString(SheetReferences refs)
{
return this.GREATERTHAN;
}
/**
* Implementation of method from OperationsPtg
* @param operands a String array of operands
* @return String the Formula as a String
*/
public String toFormulaString(String[] operands)
{
StringBuffer buffer = new StringBuffer();
buffer.append(operands[ 0 ]);
buffer.append(this.GREATERTHAN);
buffer.append(operands[ 1 ]);
return buffer.toString();
}
/**
* Get the default operands class value
* @return byte the Ptg Class Value as a byte from the Ptg Parent object
*/
public byte getDefaultOperandClass()
{
return Ptg.CLASS_VALUE;
}
/**
* Implementation of clone method from Object
* @return Object a clone of this class as an Object
*/
public Object clone()
{
return new GreaterThanPtg();
}
}

View File

@ -0,0 +1,185 @@
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache POI" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* "Apache POI", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
/*
* LessThanPtg.java
*
* Created on January 23, 2003, 9:47 AM
*/
package org.apache.poi.hssf.record.formula;
//JDK
import java.util.List;
//POI
import org.apache.poi.hssf.util.SheetReferences;
/**
* Less than operator PTG "<". The SID is taken from the
* Openoffice.orgs Documentation of the Excel File Format,
* Table 3.5.7
* @author Cameron Riley (criley at ekmail.com)
*/
public class LessThanPtg
extends OperationPtg
{
/** the size of the Ptg */
public final static int SIZE = 1;
/** the sid for the less than operator as hex */
public final static byte sid = 0x09;
/** identifier for LESS THAN char */
private final static String LESSTHAN = "<";
/**
* Constructor. Creates new LessThanPtg
*/
public LessThanPtg()
{
//deliberately empty
}
/**
* Constructor. Create a new LessThanPtg.
* @param data the byte array to have the PTG added to
* @param offset the offset to the PTG to.
*/
public LessThanPtg(byte [] data, int offset)
{
//deliberately empty
}
/**
* Write the sid to an array
* @param array the array of bytes to write the sid to
* @param offset the offset to add the sid to
*/
public void writeBytes(byte[] array, int offset)
{
array[ offset + 0 ] = sid;
}
/**
* Get the size of the sid
* @return int the size of the sid in terms of byte additions to an array
*/
public int getSize()
{
return SIZE;
}
/**
* Get the type of PTG for Less Than
* @return int the identifier for the type
*/
public int getType()
{
return TYPE_BINARY;
}
/**
* Get the number of operands for the Less than operator
* @return int the number of operands
*/
public int getNumberOfOperands()
{
return 2;
}
/**
* Implementation of method from Ptg
* @param refs the Sheet References
*/
public String toFormulaString(SheetReferences refs)
{
return this.LESSTHAN;
}
/**
* Implementation of method from OperationsPtg
* @param operands a String array of operands
* @return String the Formula as a String
*/
public String toFormulaString(String[] operands)
{
StringBuffer buffer = new StringBuffer();
buffer.append(operands[ 0 ]);
buffer.append(this.LESSTHAN);
buffer.append(operands[ 1 ]);
return buffer.toString();
}
/**
* Get the default operands class value
* @return byte the Ptg Class Value as a byte from the Ptg Parent object
*/
public byte getDefaultOperandClass()
{
return Ptg.CLASS_VALUE;
}
/**
* Implementation of clone method from Object
* @return Object a clone of this class as an Object
*/
public Object clone()
{
return new LessThanPtg();
}
}

View File

@ -177,6 +177,14 @@ public abstract class Ptg
retval = new EqualPtg(data, offset); retval = new EqualPtg(data, offset);
break; break;
case GreaterThanPtg.sid:
retval = new GreaterThanPtg(data, offset);
break;
case LessThanPtg.sid:
retval = new LessThanPtg(data, offset);
break;
case ConcatPtg.sid : case ConcatPtg.sid :
retval = new ConcatPtg(data, offset); retval = new ConcatPtg(data, offset);
break; break;

View File

@ -251,6 +251,17 @@ public class TestFormulaParser extends TestCase {
} }
public void testSimpleLogical() {
FormulaParser fp=new FormulaParser("IF(A1<A2,B1,B2)",null);
fp.parse();
Ptg[] ptgs = fp.getRPNPtg();
assertTrue("Ptg array should not be null", ptgs !=null);
assertEquals("Ptg array length", 9, ptgs.length);
assertEquals("3rd Ptg is less than",LessThanPtg.class,ptgs[2].getClass());
}
public static void main(String [] args) { public static void main(String [] args) {
System.out.println("Testing org.apache.poi.hssf.record.formula.FormulaParser"); System.out.println("Testing org.apache.poi.hssf.record.formula.FormulaParser");
junit.textui.TestRunner.run(TestFormulaParser.class); junit.textui.TestRunner.run(TestFormulaParser.class);

View File

@ -849,6 +849,36 @@ extends TestCase {
in.close(); in.close();
} }
public void testLogicalFormulas()
throws java.io.IOException
{
File file = File.createTempFile("testLogicalFormula",".xls");
FileOutputStream out = new FileOutputStream(file);
HSSFWorkbook wb = new HSSFWorkbook();
HSSFSheet s = wb.createSheet("A");
HSSFRow r = null;
HSSFCell c = null;
r = s.createRow((short)0);
c=r.createCell((short)1); c.setCellFormula("IF(A1<A2,B1,B2)");
wb.write(out);
out.close();
assertTrue("file exists",file.exists());
FileInputStream in = new FileInputStream(file);
wb = new HSSFWorkbook(in);
s = wb.getSheetAt(0);
r = s.getRow(0);
c = r.getCell((short)1);
assertEquals("Formula in cell 1 ","IF(A1<A2,B1,B2)",c.getCellFormula());
in.close();
}
public void testDateFormulas() public void testDateFormulas()
throws java.io.IOException throws java.io.IOException
{ {