]> source.dussan.org Git - poi.git/commitdiff
Refactored TextFunctions. Some minor fixes - test cases added.
authorJosh Micich <josh@apache.org>
Sat, 13 Sep 2008 05:14:26 +0000 (05:14 +0000)
committerJosh Micich <josh@apache.org>
Sat, 13 Sep 2008 05:14:26 +0000 (05:14 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@694877 13f79535-47bb-0310-9956-ffa450edef68

19 files changed:
src/java/org/apache/poi/hssf/record/formula/eval/ConcatEval.java
src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
src/java/org/apache/poi/hssf/record/formula/eval/OperandResolver.java
src/java/org/apache/poi/hssf/record/formula/functions/Concatenate.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/Exact.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/Left.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/Len.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/Lower.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/Mid.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/Replace.java
src/java/org/apache/poi/hssf/record/formula/functions/Right.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/Substitute.java
src/java/org/apache/poi/hssf/record/formula/functions/TextFunction.java
src/java/org/apache/poi/hssf/record/formula/functions/Trim.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/Upper.java [deleted file]
src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls
src/testcases/org/apache/poi/hssf/record/formula/functions/TestLen.java
src/testcases/org/apache/poi/hssf/record/formula/functions/TestMid.java
src/testcases/org/apache/poi/hssf/record/formula/functions/TestTrim.java

index 8d6729352bf86401142fc45d0c469be39f792e10..6755cfafef926465fb0f9b59204f65f3850b62aa 100644 (file)
@@ -44,7 +44,7 @@ public final class ConcatEval implements OperationEval {
                            if (ve instanceof StringValueEval) {
                                StringValueEval sve = (StringValueEval) ve;
                                sb.append(sve.getStringValue());
-                           } else if (ve instanceof BlankEval) {
+                           } else if (ve == BlankEval.INSTANCE) {
                                // do nothing
                            } else { // must be an error eval
                                throw new RuntimeException("Unexpected value type (" 
index 719349a1c8de97660809547d2b2b24bbcb042a97..e68b8ee67dd7b7dd76163ae1fbac5818dc7dceda 100644 (file)
@@ -105,8 +105,8 @@ public abstract class FunctionEval implements OperationEval {
         retval[28] = new Lookup(); // LOOKUP
         retval[29] = new Index(); // INDEX
         retval[30] = new Rept(); // REPT
-        retval[31] = new Mid(); // MID
-        retval[32] = new Len(); // LEN
+        retval[31] = TextFunction.MID;
+        retval[32] = TextFunction.LEN;
         retval[33] = new Value(); // VALUE
         retval[34] = new True(); // TRUE
         retval[35] = new False(); // FALSE
@@ -185,13 +185,13 @@ public abstract class FunctionEval implements OperationEval {
         retval[109] = NumericFunction.LOG;
         retval[110] = new Exec(); // EXEC
         retval[111] = new Char(); // CHAR
-        retval[112] = new Lower(); // LOWER
-        retval[113] = new Upper(); // UPPER
+        retval[112] = TextFunction.LOWER;
+        retval[113] = TextFunction.UPPER;
         retval[114] = new Proper(); // PROPER
-        retval[115] = new Left(); // LEFT
-        retval[116] = new Right(); // RIGHT
-        retval[117] = new Exact(); // EXACT
-        retval[118] = new Trim(); // TRIM
+        retval[115] = TextFunction.LEFT;
+        retval[116] = TextFunction.RIGHT;
+        retval[117] = TextFunction.EXACT;
+        retval[118] = TextFunction.TRIM;
         retval[119] = new Replace(); // REPLACE
         retval[120] = new Substitute(); // SUBSTITUTE
         retval[121] = new Code(); // CODE
@@ -394,7 +394,7 @@ public abstract class FunctionEval implements OperationEval {
         retval[332] = new Tinv(); // TINV
         retval[334] = new NotImplementedFunction(); // MOVIECOMMAND
         retval[335] = new NotImplementedFunction(); // GETMOVIE
-        retval[336] = new Concatenate(); // CONCATENATE
+        retval[336] = TextFunction.CONCATENATE;
         retval[337] = NumericFunction.POWER;
         retval[338] = new NotImplementedFunction(); // PIVOTADDDATA
         retval[339] = new NotImplementedFunction(); // GETPIVOTTABLE
index 87f45236bfac4a5086ff7206e55962c92842091f..09be70477f0694c8a16845ea9ad488f9524ed46c 100755 (executable)
@@ -272,12 +272,7 @@ public final class OperandResolver {
                        StringValueEval sve = (StringValueEval) ve;
                        return sve.getStringValue();
                }
-               if (ve instanceof NumberEval) {
-                       NumberEval neval = (NumberEval) ve;
-                       return neval.getStringValue();
-               } 
-
-               if (ve instanceof BlankEval) {
+               if (ve == BlankEval.INSTANCE) {
                        return "";
                }
                throw new IllegalArgumentException("Unexpected eval class (" + ve.getClass().getName() + ")");
@@ -289,7 +284,7 @@ public final class OperandResolver {
         */
        public static Boolean coerceValueToBoolean(ValueEval ve, boolean stringsAreBlanks) throws EvaluationException {
 
-               if (ve == null || ve instanceof BlankEval) {
+               if (ve == null || ve == BlankEval.INSTANCE) {
                        // TODO - remove 've == null' condition once AreaEval is fixed
                        return null;
                }
@@ -297,7 +292,7 @@ public final class OperandResolver {
                        return Boolean.valueOf(((BoolEval) ve).getBooleanValue());
                }
 
-               if (ve instanceof BlankEval) {
+               if (ve == BlankEval.INSTANCE) {
                        return null;
                }
 
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Concatenate.java b/src/java/org/apache/poi/hssf/record/formula/functions/Concatenate.java
deleted file mode 100644 (file)
index be961c1..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-import org.apache.poi.hssf.record.formula.eval.BlankEval;
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.StringEval;
-import org.apache.poi.hssf.record.formula.eval.StringValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
- */
-public class Concatenate extends TextFunction {
-
-
-    public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
-        ValueEval retval = null;
-        StringBuffer sb = new StringBuffer();
-        
-        for (int i=0, iSize=operands.length; i<iSize; i++) {
-            ValueEval ve = singleOperandEvaluate(operands[i], srcCellRow, srcCellCol);
-            if (ve instanceof StringValueEval) {
-                StringValueEval sve = (StringValueEval) ve;
-                sb.append(sve.getStringValue());
-            }
-            else if (ve instanceof BlankEval) {}
-            else {
-                retval = ErrorEval.VALUE_INVALID;
-                break;
-            }
-        }
-        
-        if (retval == null) {
-            retval = new StringEval(sb.toString());
-        }
-        
-        return retval;
-    }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Exact.java b/src/java/org/apache/poi/hssf/record/formula/functions/Exact.java
deleted file mode 100644 (file)
index 63dc18d..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-import org.apache.poi.hssf.record.formula.eval.BlankEval;
-import org.apache.poi.hssf.record.formula.eval.BoolEval;
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.StringEval;
-import org.apache.poi.hssf.record.formula.eval.StringValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
- */
-public class Exact extends TextFunction {
-
-
-    public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
-        ValueEval retval = null;
-        String s0 = null;
-        String s1 = null;
-        
-        switch (operands.length) {
-        default:
-            retval = ErrorEval.VALUE_INVALID;
-            break;
-        case 2:
-            ValueEval ve = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
-            if (ve instanceof StringValueEval) {
-                StringValueEval sve = (StringValueEval) ve;
-                s0 = sve.getStringValue();
-            }
-            else if (ve instanceof BlankEval) {
-                s0 = StringEval.EMPTY_INSTANCE.getStringValue();
-            }
-            else {
-                retval = ErrorEval.VALUE_INVALID;
-                break;
-            }
-
-            if (retval == null) {
-                ve = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol);
-                if (ve instanceof StringValueEval) {
-                    StringValueEval sve = (StringValueEval) ve;
-                    s1 = sve.getStringValue();
-                }
-                else if (ve instanceof BlankEval) {
-                    s1 = StringEval.EMPTY_INSTANCE.getStringValue();
-                }
-                else {
-                    retval = ErrorEval.VALUE_INVALID;
-                    break;
-                }
-            }
-        }
-        
-        if (retval == null) {
-            boolean b = s0.equals(s1);
-            retval = b ? BoolEval.TRUE : BoolEval.FALSE;
-        }
-        
-        return retval;
-    }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Left.java b/src/java/org/apache/poi/hssf/record/formula/functions/Left.java
deleted file mode 100644 (file)
index ecb14a7..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-import org.apache.poi.hssf.record.formula.eval.BoolEval;
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.RefEval;
-import org.apache.poi.hssf.record.formula.eval.StringEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
- */
-public class Left extends TextFunction {
-
-    public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
-        Eval retval = ErrorEval.VALUE_INVALID;
-        int index = 1;
-        switch (operands.length) {
-        default:
-            break;
-        case 2:
-            Eval indexEval = operands[1];
-            index = evaluateAsInteger(indexEval);
-            if (index < 0) {
-                break;
-            }
-        case 1:
-            ValueEval veval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
-            String str = null;
-            if (veval instanceof StringEval) {
-                StringEval stringEval = (StringEval) veval;
-                str = stringEval.getStringValue();
-            }
-            else if (veval instanceof BoolEval) {
-                BoolEval beval = (BoolEval) veval;
-                str = beval.getBooleanValue() ? "TRUE" : "FALSE";
-            }
-            else if (veval instanceof NumberEval) {
-                NumberEval neval = (NumberEval) veval;
-                str = neval.getStringValue();
-            }
-            if (null != str) {
-                str = str.substring(0, Math.min(str.length(), index));
-                retval = new StringEval(str);
-            }
-        }
-        return retval;
-    }
-    
-    protected int evaluateAsInteger(Eval eval) {
-        int numval = -1;
-        if (eval instanceof NumberEval) {
-            NumberEval neval = (NumberEval) eval;
-            double d = neval.getNumberValue();
-            numval = (int) d;
-        }
-        else if (eval instanceof StringEval) {
-            StringEval seval = (StringEval) eval;
-            String s = seval.getStringValue();
-            try { 
-                double d = Double.parseDouble(s);
-                numval = (int) d;
-            } 
-            catch (Exception e) {
-            }
-        }
-        else if (eval instanceof BoolEval) {
-            BoolEval beval = (BoolEval) eval;
-            numval = beval.getBooleanValue() ? 1 : 0;
-        }
-        else if (eval instanceof RefEval) {
-            numval = evaluateAsInteger(xlateRefEval((RefEval) eval));
-        }
-        return numval;
-    }
-    
-    protected Eval xlateRefEval(RefEval reval) {
-        Eval retval = reval.getInnerValueEval();
-        
-        if (retval instanceof RefEval) {
-            retval = xlateRefEval((RefEval) retval);
-        }
-        return retval;
-    }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Len.java b/src/java/org/apache/poi/hssf/record/formula/functions/Len.java
deleted file mode 100644 (file)
index 0bc49b4..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-package org.apache.poi.hssf.record.formula.functions;
-
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.EvaluationException;
-import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.OperandResolver;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
- */
-public final class Len extends TextFunction {
-
-       public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
-               
-               if(args.length != 1) {
-                       return ErrorEval.VALUE_INVALID;
-               }
-               
-               try {
-                       ValueEval veval = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
-
-                       String str = OperandResolver.coerceValueToString(veval);
-                       
-                       return new NumberEval(str.length());
-               } catch (EvaluationException e) {
-                       return e.getErrorEval();
-               }
-       }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Lower.java b/src/java/org/apache/poi/hssf/record/formula/functions/Lower.java
deleted file mode 100644 (file)
index edf7e27..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-import org.apache.poi.hssf.record.formula.eval.BlankEval;
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.StringEval;
-import org.apache.poi.hssf.record.formula.eval.StringValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
- */
-public class Lower extends TextFunction {
-
-
-    public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
-        ValueEval retval = null;
-        String s = null;
-        
-        switch (operands.length) {
-        default:
-            retval = ErrorEval.VALUE_INVALID;
-            break;
-        case 1:
-            ValueEval ve = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
-            if (ve instanceof StringValueEval) {
-                StringValueEval sve = (StringValueEval) ve;
-                s = sve.getStringValue();
-            }
-            else if (ve instanceof BlankEval) {}
-            else {
-                retval = ErrorEval.VALUE_INVALID;
-                break;
-            }
-        }
-        
-        if (retval == null) {
-            s = (s == null) ? EMPTY_STRING : s;
-            retval = new StringEval(s.toLowerCase());
-        }
-        
-        return retval;
-    }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Mid.java b/src/java/org/apache/poi/hssf/record/formula/functions/Mid.java
deleted file mode 100644 (file)
index b9d679d..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.poi.hssf.record.formula.functions;
-
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.EvaluationException;
-import org.apache.poi.hssf.record.formula.eval.OperandResolver;
-import org.apache.poi.hssf.record.formula.eval.StringEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * An implementation of the MID function<br/> MID returns a specific number of
- * characters from a text string, starting at the specified position.<p/>
- * 
- * <b>Syntax<b>:<br/> <b>MID</b>(<b>text</b>, <b>start_num</b>,
- * <b>num_chars</b>)<br/>
- * 
- * @author Manda Wilson &lt; wilson at c bio dot msk cc dot org &gt;
- */
-public class Mid implements Function {
-       /**
-        * Returns a specific number of characters from a text string, starting at
-        * the position you specify, based on the number of characters you specify.
-        * 
-        * @see org.apache.poi.hssf.record.formula.eval.Eval
-        */
-       public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
-               if (args.length != 3) {
-                       return ErrorEval.VALUE_INVALID;
-               }
-
-               String text;
-               int startIx; // zero based
-               int numChars;
-
-               try {
-                       ValueEval evText = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
-                       text = OperandResolver.coerceValueToString(evText);
-                       int startCharNum = evaluateNumberArg(args[1], srcCellRow, srcCellCol);
-                       numChars = evaluateNumberArg(args[2], srcCellRow, srcCellCol);
-                       startIx = startCharNum - 1; // convert to zero-based
-               } catch (EvaluationException e) {
-                       return e.getErrorEval();
-               }
-
-               int len = text.length();
-               if (startIx < 0) {
-                       return ErrorEval.VALUE_INVALID;
-               }
-               if (numChars < 0) {
-                       return ErrorEval.VALUE_INVALID;
-               }
-               if (numChars < 0 || startIx > len) {
-                       return new StringEval("");
-               }
-               int endIx = startIx + numChars;
-               if (endIx > len) {
-                       endIx = len;
-               }
-               String result = text.substring(startIx, endIx);
-               return new StringEval(result);
-
-       }
-
-       private static int evaluateNumberArg(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
-               ValueEval ev = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
-               // Note - for start_num arg, blank/zero causes error(#VALUE!),
-               // but for num_chars causes empty string to be returned.
-               return OperandResolver.coerceValueToInt(ev);
-       }
-}
\ No newline at end of file
index 95413f08238bb1d4f088b6e82e1dbe493445aad9..1dfc4f8f0571d55f9e9c6d6d9e002ed20ef6c8f1 100644 (file)
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-/*
- * Created on May 15, 2005
- *
- */
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
 package org.apache.poi.hssf.record.formula.functions;
 
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
 import org.apache.poi.hssf.record.formula.eval.StringEval;
-import org.apache.poi.hssf.record.formula.eval.StringValueEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
 /**
- * An implementation of the REPLACE function:
- * Replaces part of a text string based on the number of characters 
- * you specify, with another text string.
+ * An implementation of the Excel REPLACE() function<p/>:
+ * Replaces part of a text string based on the number of characters
+ * you specify, with another text string.<br/>
+ *
+ * <b>Syntax</b>:<br/>
+ * <b>REPLACE</b>(<b>oldText</b>, <b>startNum</b>, <b>numChars</b>, <b>newText</b>)<p/>
+ *
+ * <b>oldText</b>  The text string containing characters to replace<br/>
+ * <b>startNum</b> The position of the first character to replace (1-based)<br/>
+ * <b>numChars</b> The number of characters to replace<br/>
+ * <b>newText</b> The new text value to replace the removed section<br/>
+ *
  * @author Manda Wilson &lt; wilson at c bio dot msk cc dot org &gt;
  */
-public class Replace extends TextFunction {
+public final class Replace extends TextFunction {
+
+       protected ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol)
+               throws EvaluationException {
+               if (args.length != 4) {
+                       return ErrorEval.VALUE_INVALID;
+               }
 
-       /**
-        * Replaces part of a text string based on the number of characters 
-        * you specify, with another text string.
-        * 
-        * @see org.apache.poi.hssf.record.formula.eval.Eval
-        */
-    public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {          
-       Eval retval = null;
-        String oldStr = null;
-        String newStr = null;
-        int startNum = 0;
-        int numChars = 0;
-        
-        switch (operands.length) {
-               default:
-                   retval = ErrorEval.VALUE_INVALID;
-               case 4:         
-                       // first operand is text string containing characters to replace
-                   // second operand is position of first character to replace
-                   // third operand is the number of characters in the old string
-                   // you want to replace with new string
-                   // fourth operand is the new string
-                   ValueEval firstveval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
-                   ValueEval secondveval = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol);
-                   ValueEval thirdveval = singleOperandEvaluate(operands[2], srcCellRow, srcCellCol);
-                   ValueEval fourthveval = singleOperandEvaluate(operands[3], srcCellRow, srcCellCol);
-                   if (firstveval instanceof StringValueEval
-                       && secondveval instanceof NumericValueEval
-                       && thirdveval instanceof NumericValueEval
-                       && fourthveval instanceof StringValueEval) {
-                       
-                       StringValueEval oldStrEval = (StringValueEval) firstveval;
-                       oldStr = oldStrEval.getStringValue();
-                       
-                       NumericValueEval startNumEval = (NumericValueEval) secondveval;
-                       // NOTE: it is safe to cast to int here
-                       // because in Excel =REPLACE("task", 2.7, 3, "est") 
-                       // returns test 
-                       // so 2.7 must be truncated to 2
-                       // and =REPLACE("task", 1, 1.9, "") returns ask 
-                       // so 1.9 must be truncated to 1
-                       startNum = (int) startNumEval.getNumberValue();
-                       
-                       NumericValueEval numCharsEval = (NumericValueEval) thirdveval;
-                       numChars = (int) numCharsEval.getNumberValue();
-                                    
-                       StringValueEval newStrEval = (StringValueEval) fourthveval;
-                       newStr = newStrEval.getStringValue();
-                   } else {
-                       retval = ErrorEval.VALUE_INVALID;
-                   }
-           }
-               
-        if (retval == null) {
-                       if (startNum < 1 || numChars < 0) {
-                               retval = ErrorEval.VALUE_INVALID;
-                       } else {
-                               StringBuffer strBuff = new StringBuffer(oldStr);
-                               // remove any characters that should be replaced
-                               if (startNum <= oldStr.length() && numChars != 0) {
-                                       strBuff.delete(startNum - 1, startNum - 1 + numChars);
-                               } 
-                               // now insert (or append) newStr
-                               if (startNum > strBuff.length()) {
-                                       strBuff.append(newStr);
-                               } else {
-                                       strBuff.insert(startNum - 1, newStr);
-                               }
-                               retval = new StringEval(strBuff.toString());
-                       }
-        } 
-               return retval;
-    }
+               String oldStr = evaluateStringArg(args[0], srcCellRow, srcCellCol);
+               int startNum = evaluateIntArg(args[1], srcCellRow, srcCellCol);
+               int numChars = evaluateIntArg(args[2], srcCellRow, srcCellCol);
+               String newStr = evaluateStringArg(args[3], srcCellRow, srcCellCol);
 
+               if (startNum < 1 || numChars < 0) {
+                       return ErrorEval.VALUE_INVALID;
+               }
+               StringBuffer strBuff = new StringBuffer(oldStr);
+               // remove any characters that should be replaced
+               if (startNum <= oldStr.length() && numChars != 0) {
+                       strBuff.delete(startNum - 1, startNum - 1 + numChars);
+               }
+               // now insert (or append) newStr
+               if (startNum > strBuff.length()) {
+                       strBuff.append(newStr);
+               } else {
+                       strBuff.insert(startNum - 1, newStr);
+               }
+               return new StringEval(strBuff.toString());
+       }
 }
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Right.java b/src/java/org/apache/poi/hssf/record/formula/functions/Right.java
deleted file mode 100644 (file)
index 771d045..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-import org.apache.poi.hssf.record.formula.eval.BoolEval;
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.RefEval;
-import org.apache.poi.hssf.record.formula.eval.StringEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
- */
-public class Right extends TextFunction {
-
-    public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
-        Eval retval = ErrorEval.VALUE_INVALID;
-        int index = 1;
-        switch (operands.length) {
-        default:
-            break;
-        case 2:
-            Eval indexEval = operands[1];
-            index = evaluateAsInteger(indexEval);
-            if (index < 0) {
-                break;
-            }
-        case 1:
-            ValueEval veval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
-            String str = null;
-            if (veval instanceof StringEval) {
-                StringEval stringEval = (StringEval) veval;
-                str = stringEval.getStringValue();
-            }
-            else if (veval instanceof BoolEval) {
-                BoolEval beval = (BoolEval) veval;
-                str = beval.getBooleanValue() ? "TRUE" : "FALSE";
-            }
-            else if (veval instanceof NumberEval) {
-                NumberEval neval = (NumberEval) veval;
-                str = neval.getStringValue();
-            }
-            if (null != str) {
-                int strlen = str.length();
-                str = str.substring(Math.max(0, strlen-index));
-                retval = new StringEval(str);
-            }
-        }
-        return retval;
-    }
-    
-    protected int evaluateAsInteger(Eval eval) {
-        int numval = -1;
-        if (eval instanceof NumberEval) {
-            NumberEval neval = (NumberEval) eval;
-            double d = neval.getNumberValue();
-            numval = (int) d;
-        }
-        else if (eval instanceof StringEval) {
-            StringEval seval = (StringEval) eval;
-            String s = seval.getStringValue();
-            try { 
-                double d = Double.parseDouble(s);
-                numval = (int) d;
-            } 
-            catch (Exception e) {
-            }
-        }
-        else if (eval instanceof BoolEval) {
-            BoolEval beval = (BoolEval) eval;
-            numval = beval.getBooleanValue() ? 1 : 0;
-        }
-        else if (eval instanceof RefEval) {
-            numval = evaluateAsInteger(xlateRefEval((RefEval) eval));
-        }
-        return numval;
-    }
-    
-    protected Eval xlateRefEval(RefEval reval) {
-        Eval retval = reval.getInnerValueEval();
-        
-        if (retval instanceof RefEval) {
-            retval = xlateRefEval((RefEval) retval);
-        }
-        return retval;
-    }
-}
index 9d2e9ce3618a1a2d570a8c90f670ec268e9e1620..b00d7510e319c77b372ee6f3871e65a779ab7c54 100644 (file)
@@ -1,30 +1,26 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-/*
- * Created on May 15, 2005
- *
- */
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
 package org.apache.poi.hssf.record.formula.functions;
 
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
 import org.apache.poi.hssf.record.formula.eval.StringEval;
-import org.apache.poi.hssf.record.formula.eval.StringValueEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
 /**
@@ -32,86 +28,75 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
  * Substitutes text in a text string with new text, some number of times.
  * @author Manda Wilson &lt; wilson at c bio dot msk cc dot org &gt;
  */
-public class Substitute extends TextFunction {
-       private static final int REPLACE_ALL = -1;
-       
-       /**
-        *Substitutes text in a text string with new text, some number of times.
-        * 
-        * @see org.apache.poi.hssf.record.formula.eval.Eval
-        */
-    public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {          
-       Eval retval = null;
-        String oldStr = null;
-        String searchStr = null;
-        String newStr = null;
-        int numToReplace = REPLACE_ALL;
-        
-        switch (operands.length) {
-               default:
-                   retval = ErrorEval.VALUE_INVALID;
-               case 4:
-                       ValueEval fourthveval = singleOperandEvaluate(operands[3], srcCellRow, srcCellCol);
-                       if (fourthveval instanceof NumericValueEval) {
-                               NumericValueEval numToReplaceEval = (NumericValueEval) fourthveval;
-                               // NOTE: it is safe to cast to int here
-                       // because in Excel =SUBSTITUTE("teststr","t","T",1.9) 
-                       // returns Teststr 
-                       // so 1.9 must be truncated to 1
-                               numToReplace = (int) numToReplaceEval.getNumberValue();
-                       } else {
-                               retval = ErrorEval.VALUE_INVALID;
-                       }
-               case 3: 
-                       // first operand is text string containing characters to replace
-                   // second operand is text to find
-                   // third operand is replacement text
-                   ValueEval firstveval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
-                   ValueEval secondveval = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol);
-                   ValueEval thirdveval = singleOperandEvaluate(operands[2], srcCellRow, srcCellCol);
-                   if (firstveval instanceof StringValueEval
-                       && secondveval instanceof StringValueEval
-                       && thirdveval instanceof StringValueEval) {
-                       
-                       StringValueEval oldStrEval = (StringValueEval) firstveval;
-                       oldStr = oldStrEval.getStringValue();
-                       
-                       StringValueEval searchStrEval = (StringValueEval) secondveval;
-                       searchStr = searchStrEval.getStringValue();
-                       
-                       StringValueEval newStrEval = (StringValueEval) thirdveval;
-                       newStr = newStrEval.getStringValue();
-                   } else {
-                       retval = ErrorEval.VALUE_INVALID;
-                   }
-           }
-               
-        if (retval == null) {
-                       if (numToReplace != REPLACE_ALL && numToReplace < 1) {
-                               retval = ErrorEval.VALUE_INVALID;
-                       } else if (searchStr.length() == 0) {
-                               retval = new StringEval(oldStr);
-                       } else {
-                               StringBuffer strBuff = new StringBuffer();
-                               int startIndex = 0;
-                               int nextMatch = -1;
-                               for (int leftToReplace = numToReplace; 
-                                       (leftToReplace > 0 || numToReplace == REPLACE_ALL) 
-                                               && (nextMatch = oldStr.indexOf(searchStr, startIndex)) != -1;
-                                       leftToReplace--) {
-                                       // store everything from end of last match to start of this match
-                                       strBuff.append(oldStr.substring(startIndex, nextMatch));
-                                       strBuff.append(newStr);
-                                       startIndex = nextMatch + searchStr.length();
+public final class Substitute extends TextFunction {
+
+       protected ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol)
+                       throws EvaluationException {
+               if (args.length < 3 || args.length > 4) {
+                       return ErrorEval.VALUE_INVALID;
+               }
+
+               String oldStr = evaluateStringArg(args[0], srcCellRow, srcCellCol);
+               String searchStr = evaluateStringArg(args[1], srcCellRow, srcCellCol);
+               String newStr = evaluateStringArg(args[2], srcCellRow, srcCellCol);
+
+               String result;
+               switch (args.length) {
+                       default:
+                               throw new IllegalStateException("Cannot happen");
+                       case 4:
+                               int instanceNumber = evaluateIntArg(args[3], srcCellRow, srcCellCol);
+                               if (instanceNumber < 1) {
+                                       return ErrorEval.VALUE_INVALID;
                                }
+                               result = replaceOneOccurrence(oldStr, searchStr, newStr, instanceNumber);
+                               break;
+                       case 3:
+                               result = replaceAllOccurrences(oldStr, searchStr, newStr);
+               }
+               return new StringEval(result);
+       }
+
+       private static String replaceAllOccurrences(String oldStr, String searchStr, String newStr) {
+               StringBuffer sb = new StringBuffer();
+               int startIndex = 0;
+               int nextMatch = -1;
+               while (true) {
+                       nextMatch = oldStr.indexOf(searchStr, startIndex);
+                       if (nextMatch < 0) {
                                // store everything from end of last match to end of string
-                               if (startIndex < oldStr.length()) {
-                                       strBuff.append(oldStr.substring(startIndex));
-                               }
-                               retval = new StringEval(strBuff.toString());
+                               sb.append(oldStr.substring(startIndex));
+                               return sb.toString();
+                       }
+                       // store everything from end of last match to start of this match
+                       sb.append(oldStr.substring(startIndex, nextMatch));
+                       sb.append(newStr);
+                       startIndex = nextMatch + searchStr.length();
+               }
+       }
+
+       private static String replaceOneOccurrence(String oldStr, String searchStr, String newStr, int instanceNumber) {
+               if (searchStr.length() < 1) {
+                       return oldStr;
+               }
+               int startIndex = 0;
+               int nextMatch = -1;
+               int count=0;
+               while (true) {
+                       nextMatch = oldStr.indexOf(searchStr, startIndex);
+                       if (nextMatch < 0) {
+                               // not enough occurrences found - leave unchanged
+                               return oldStr;
+                       }
+                       count++;
+                       if (count == instanceNumber) {
+                               StringBuffer sb = new StringBuffer(oldStr.length() + newStr.length());
+                               sb.append(oldStr.substring(0, nextMatch));
+                               sb.append(newStr);
+                               sb.append(oldStr.substring(nextMatch + searchStr.length()));
+                               return sb.toString();
                        }
-        } 
-               return retval;
-    }
-    
+                       startIndex = nextMatch + searchStr.length();
+               }
+       }
 }
index 9da17761275c4f521cfc5b19a0248c607c821425..df7db7ad32892b8e96f92d3674fa3f0db9831bb1 100644 (file)
@@ -1,31 +1,29 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-/*
- * Created on May 22, 2005
- *
- */
+/* ====================================================================
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to You under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+==================================================================== */
+
 package org.apache.poi.hssf.record.formula.functions;
 
-import org.apache.poi.hssf.record.formula.eval.AreaEval;
-import org.apache.poi.hssf.record.formula.eval.BlankEval;
+import org.apache.poi.hssf.record.formula.eval.BoolEval;
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.RefEval;
-import org.apache.poi.hssf.record.formula.eval.StringValueEval;
+import org.apache.poi.hssf.record.formula.eval.EvaluationException;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.OperandResolver;
+import org.apache.poi.hssf.record.formula.eval.StringEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
 /**
@@ -33,75 +31,164 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
  *
  */
 public abstract class TextFunction implements Function {
-    
-    protected static final String EMPTY_STRING = "";
-    
-    protected ValueEval singleOperandEvaluate(Eval eval, int srcRow, short srcCol) {
-        ValueEval retval;
-        if (eval instanceof AreaEval) {
-            AreaEval ae = (AreaEval) eval;
-            if (ae.contains(srcRow, srcCol)) { // circular ref!
-                retval = ErrorEval.CIRCULAR_REF_ERROR;
-            }
-            else if (ae.isRow()) {
-                if (ae.containsColumn(srcCol)) {
-                    ValueEval ve = ae.getValueAt(ae.getFirstRow(), srcCol);
-                    retval = attemptXlateToText(ve);
-                }
-                else {
-                    retval = ErrorEval.VALUE_INVALID;
-                }
-            }
-            else if (ae.isColumn()) {
-                if (ae.containsRow(srcRow)) {
-                    ValueEval ve = ae.getValueAt(srcRow, ae.getFirstColumn());
-                    retval = attemptXlateToText(ve);
-                }
-                else {
-                    retval = ErrorEval.VALUE_INVALID;
-                }
-            }
-            else {
-                retval = ErrorEval.VALUE_INVALID;
-            }
-        }
-        else {
-            retval = attemptXlateToText((ValueEval) eval);
-        }
-        return retval;
-    }
-
-    
-    /**
-     * converts from Different ValueEval types to StringEval.
-     * Note: AreaEvals are not handled, if arg is an AreaEval,
-     * the returned value is ErrorEval.VALUE_INVALID
-     * @param ve
-     */
-    protected ValueEval attemptXlateToText(ValueEval ve) {
-        ValueEval retval;
-        if (ve instanceof StringValueEval) {
-            retval = ve;
-        }
-        else if (ve instanceof RefEval) {
-            RefEval re = (RefEval) ve;
-            ValueEval ive = re.getInnerValueEval();
-            if (ive instanceof StringValueEval) {
-                retval = ive;
-            }
-            else if (ive instanceof BlankEval) {
-                retval = ive;
-            }
-            else {
-                retval = ErrorEval.VALUE_INVALID;
-            }
-        }
-        else if (ve instanceof BlankEval) {
-            retval = ve;
-        }
-        else {
-            retval = ErrorEval.VALUE_INVALID;
-        }
-        return retval;
-    }
+
+       protected static final String EMPTY_STRING = "";
+
+       protected static final String evaluateStringArg(Eval eval, int srcRow, short srcCol) throws EvaluationException {
+               ValueEval ve = OperandResolver.getSingleValue(eval, srcRow, srcCol);
+               return OperandResolver.coerceValueToString(ve);
+       }
+       protected static final int evaluateIntArg(Eval arg, int srcCellRow, short srcCellCol) throws EvaluationException {
+               ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+               return OperandResolver.coerceValueToInt(ve);
+       }
+
+       public final Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+               try {
+                       return evaluateFunc(args, srcCellRow, srcCellCol);
+               } catch (EvaluationException e) {
+                       return e.getErrorEval();
+               }
+       }
+
+       protected abstract ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol) throws EvaluationException;
+
+       /* ---------------------------------------------------------------------- */
+       
+       private static abstract class SingleArgTextFunc extends TextFunction {
+
+               protected SingleArgTextFunc() {
+                       // no fields to initialise
+               }
+               protected ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol)
+                               throws EvaluationException {
+                       if (args.length != 1) {
+                               return ErrorEval.VALUE_INVALID;
+                       }
+                       String arg = evaluateStringArg(args[0], srcCellRow, srcCellCol);
+                       return evaluate(arg);
+               }
+               protected abstract ValueEval evaluate(String arg);
+       }
+
+       public static final Function LEN = new SingleArgTextFunc() {
+               protected ValueEval evaluate(String arg) {
+                       return new NumberEval(arg.length());
+               }
+       };
+       public static final Function LOWER = new SingleArgTextFunc() {
+               protected ValueEval evaluate(String arg) {
+                       return new StringEval(arg.toLowerCase());
+               }
+       };
+       public static final Function UPPER = new SingleArgTextFunc() {
+               protected ValueEval evaluate(String arg) {
+                       return new StringEval(arg.toUpperCase());
+               }
+       };
+       /**
+        * An implementation of the TRIM function:
+        * Removes leading and trailing spaces from value if evaluated operand
+        *  value is string.
+        * @author Manda Wilson &lt; wilson at c bio dot msk cc dot org &gt;
+        */
+       public static final Function TRIM = new SingleArgTextFunc() {
+               protected ValueEval evaluate(String arg) {
+                       return new StringEval(arg.trim());
+               }
+       };
+
+       /**
+        * An implementation of the MID function<br/>
+        * MID returns a specific number of
+        * characters from a text string, starting at the specified position.<p/>
+        * 
+        * <b>Syntax<b>:<br/> <b>MID</b>(<b>text</b>, <b>start_num</b>,
+        * <b>num_chars</b>)<br/>
+        * 
+        * @author Manda Wilson &lt; wilson at c bio dot msk cc dot org &gt;
+        */
+       public static final Function MID = new TextFunction() {
+
+               protected ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol)
+                               throws EvaluationException {
+                       if (args.length != 3) {
+                               return ErrorEval.VALUE_INVALID;
+                       }
+
+                       String text = evaluateStringArg(args[0], srcCellRow, srcCellCol);
+                       int startCharNum = evaluateIntArg(args[1], srcCellRow, srcCellCol);
+                       int numChars = evaluateIntArg(args[2], srcCellRow, srcCellCol);
+                       int startIx = startCharNum - 1; // convert to zero-based
+
+                       // Note - for start_num arg, blank/zero causes error(#VALUE!),
+                       // but for num_chars causes empty string to be returned.
+                       if (startIx < 0) {
+                               return ErrorEval.VALUE_INVALID;
+                       }
+                       if (numChars < 0) {
+                               return ErrorEval.VALUE_INVALID;
+                       }
+                       int len = text.length();
+                       if (numChars < 0 || startIx > len) {
+                               return new StringEval("");
+                       }
+                       int endIx = Math.min(startIx + numChars, len);
+                       String result = text.substring(startIx, endIx);
+                       return new StringEval(result);
+               }
+       };
+
+       private static final class LeftRight extends TextFunction {
+
+               private final boolean _isLeft;
+               protected LeftRight(boolean isLeft) {
+                       _isLeft = isLeft;
+               }
+               protected ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol)
+                               throws EvaluationException {
+                       if (args.length != 2) {
+                               return ErrorEval.VALUE_INVALID;
+                       }
+                       String arg = evaluateStringArg(args[0], srcCellRow, srcCellCol);
+                       int index = evaluateIntArg(args[1], srcCellRow, srcCellCol);
+
+                       String result;
+                       if (_isLeft) {
+                               result = arg.substring(0, Math.min(arg.length(), index));
+                       } else {
+                               result = arg.substring(Math.max(0, arg.length()-index));
+                       }
+                       return new StringEval(result);
+               }
+       }
+
+       public static final Function LEFT = new LeftRight(true);
+       public static final Function RIGHT = new LeftRight(false);
+
+       public static final Function CONCATENATE = new TextFunction() {
+
+               protected ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol)
+                               throws EvaluationException {
+                       StringBuffer sb = new StringBuffer();
+                       for (int i=0, iSize=args.length; i<iSize; i++) {
+                               sb.append(evaluateStringArg(args[i], srcCellRow, srcCellCol));
+                       }
+                       return new StringEval(sb.toString());
+               }
+       };
+
+       public static final Function EXACT = new TextFunction() {
+
+               protected ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol)
+                               throws EvaluationException {
+                       if (args.length != 2) {
+                               return ErrorEval.VALUE_INVALID;
+                       }
+
+                       String s0 = evaluateStringArg(args[0], srcCellRow, srcCellCol);
+                       String s1 = evaluateStringArg(args[1], srcCellRow, srcCellCol);
+                       return BoolEval.valueOf(s0.equals(s1));
+               }
+       };
 }
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Trim.java b/src/java/org/apache/poi/hssf/record/formula/functions/Trim.java
deleted file mode 100644 (file)
index 87e29ee..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-package org.apache.poi.hssf.record.formula.functions;
-
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.EvaluationException;
-import org.apache.poi.hssf.record.formula.eval.OperandResolver;
-import org.apache.poi.hssf.record.formula.eval.StringEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * An implementation of the TRIM function:
- * Removes leading and trailing spaces from value if evaluated operand
- *  value is string.
- * @author Manda Wilson &lt; wilson at c bio dot msk cc dot org &gt;
- */
-public final class Trim extends TextFunction {
-
-       public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
-               
-               if(args.length != 1) {
-                       return ErrorEval.VALUE_INVALID;
-               }
-               
-               try {
-                       ValueEval veval = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
-
-                       String str = OperandResolver.coerceValueToString(veval);
-                       str = str.trim();
-                       if(str.length() < 1) {
-                               return StringEval.EMPTY_INSTANCE;
-                       }
-                       return new StringEval(str);
-               } catch (EvaluationException e) {
-                       return e.getErrorEval();
-               }
-       }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Upper.java b/src/java/org/apache/poi/hssf/record/formula/functions/Upper.java
deleted file mode 100644 (file)
index 5146a66..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  See the NOTICE file distributed with
-* this work for additional information regarding copyright ownership.
-* The ASF licenses this file to You under the Apache License, Version 2.0
-* (the "License"); you may not use this file except in compliance with
-* the License.  You may obtain a copy of the License at
-*
-*     http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-/*
- * Created on May 15, 2005
- *
- */
-package org.apache.poi.hssf.record.formula.functions;
-
-import org.apache.poi.hssf.record.formula.eval.BlankEval;
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.StringEval;
-import org.apache.poi.hssf.record.formula.eval.StringValueEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
- */
-public class Upper extends TextFunction {
-
-
-    public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
-        ValueEval retval = null;
-        String s = null;
-        
-        switch (operands.length) {
-        default:
-            retval = ErrorEval.VALUE_INVALID;
-            break;
-        case 1:
-            ValueEval ve = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
-            if (ve instanceof StringValueEval) {
-                StringValueEval sve = (StringValueEval) ve;
-                s = sve.getStringValue();
-            }
-            else if (ve instanceof BlankEval) {}
-            else {
-                retval = ErrorEval.VALUE_INVALID;
-                break;
-            }
-        }
-        
-        if (retval == null) {
-            s = (s == null) ? EMPTY_STRING : s;
-            retval = new StringEval(s.toUpperCase());
-        }
-        
-        return retval;
-    }
-}
index f046382eccd46b3855e3edc51fc1652731ee0f1e..f806c792f6c9b4db58c02f6a63f5bb004779663e 100644 (file)
Binary files a/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls and b/src/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls differ
index a96fb4e2b09c730489f5e610d4ad749991847d66..459d2fb555b029c066b8be08cf69f536ae0f20c7 100755 (executable)
@@ -35,7 +35,7 @@ public final class TestLen extends TestCase {
        
        private static Eval invokeLen(Eval text) {
                Eval[] args = new Eval[] { text, };
-               return new Len().evaluate(args, -1, (short)-1);
+               return TextFunction.LEN.evaluate(args, -1, (short)-1);
        }
 
        private void confirmLen(Eval text, int expected) {
index 76cd1056edef3d26bb866b4a78b9bd9e1d25764c..81e78e737c4f4a4914b31fb929386149b638e82b 100755 (executable)
@@ -38,7 +38,7 @@ public final class TestMid extends TestCase {
 
        private static Eval invokeMid(Eval text, Eval startPos, Eval numChars) {
                Eval[] args = new Eval[] { text, startPos, numChars, };
-               return new Mid().evaluate(args, -1, (short)-1);
+               return TextFunction.MID.evaluate(args, -1, (short)-1);
        }
 
        private void confirmMid(Eval text, Eval startPos, Eval numChars, String expected) {
index 076ac1fc7e4357e983febd80ac62f3c434e6e260..1c65c9ca6d95fcb6b4c740771035190699cf01c1 100755 (executable)
@@ -35,7 +35,7 @@ public final class TestTrim extends TestCase {
        
        private static Eval invokeTrim(Eval text) {
                Eval[] args = new Eval[] { text, };
-               return new Trim().evaluate(args, -1, (short)-1);
+               return TextFunction.TRIM.evaluate(args, -1, (short)-1);
        }
 
        private void confirmTrim(Eval text, String expected) {