You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ye...@apache.org on 2010/04/24 19:17:21 UTC

svn commit: r937652 - in /poi/trunk/src: documentation/content/xdocs/ java/org/apache/poi/hssf/record/formula/eval/ java/org/apache/poi/hssf/record/formula/functions/ testcases/org/apache/poi/hssf/record/formula/functions/

Author: yegor
Date: Sat Apr 24 17:17:20 2010
New Revision: 937652

URL: http://svn.apache.org/viewvc?rev=937652&view=rev
Log:
Added implementation for TEXT() and TRUNC(), see Bugzilla 49025 and 49026

Added:
    poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/TestText.java
    poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTrunc.java
Modified:
    poi/trunk/src/documentation/content/xdocs/status.xml
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/TextFunction.java

Modified: poi/trunk/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/status.xml?rev=937652&r1=937651&r2=937652&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/status.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/status.xml Sat Apr 24 17:17:20 2010
@@ -34,6 +34,8 @@
 
     <changes>
         <release version="3.7-SNAPSHOT" date="2010-??-??">
+           <action dev="POI-DEVELOPERS" type="add">49026 - Added implementation for TEXT()  </action>
+           <action dev="POI-DEVELOPERS" type="add">49025 - Added implementation for TRUNC()  </action>
            <action dev="POI-DEVELOPERS" type="fix">49147 - Properly close internal InputStream in ExtractorFactory#createExtractor(File)</action>
            <action dev="POI-DEVELOPERS" type="fix">49138 - Fixed locale-sensitive formatters in PackagePropertiesPart</action>
            <action dev="POI-DEVELOPERS" type="fix">49153 - Ensure that CTVectorVariant is included in poi-ooxml-schemas.jar</action>

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java?rev=937652&r1=937651&r2=937652&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java Sat Apr 24 17:17:20 2010
@@ -94,6 +94,7 @@ public final class FunctionEval {
 		retval[37] = BooleanFunction.OR;
 		retval[38] = BooleanFunction.NOT;
 		retval[39] = NumericFunction.MOD;
+		retval[48] = TextFunction.TEXT;
 
 		retval[56] = FinanceFunction.PV;
 		retval[57] = FinanceFunction.FV;
@@ -152,7 +153,7 @@ public final class FunctionEval {
 		retval[184] = NumericFunction.FACT;
 
 		retval[190] = LogicalFunction.ISNONTEXT;
-
+		retval[197] = NumericFunction.TRUNC;
 		retval[198] = LogicalFunction.ISLOGICAL;
 
 		retval[212] = NumericFunction.ROUNDUP;

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java?rev=937652&r1=937651&r2=937652&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java Sat Apr 24 17:17:20 2010
@@ -26,6 +26,7 @@ import org.apache.poi.hssf.record.formul
 /**
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
  * @author Josh Micich
+ * @author Stephen Wolke (smwolke at geistig.com)
  */
 public abstract class NumericFunction implements Function {
 
@@ -321,6 +322,27 @@ public abstract class NumericFunction im
 			return MathX.roundUp(d0, (int)d1);
 		}
 	};
+	static final NumberEval TRUNC_ARG2_DEFAULT = new NumberEval(0);
+	public static final Function TRUNC = new Var1or2ArgFunction() {
+
+		public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
+			return evaluate(srcRowIndex, srcColumnIndex, arg0, TRUNC_ARG2_DEFAULT);
+		}
+
+		public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
+			double result;
+			try {
+				double d0 = singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
+				double d1 = singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
+				double multi = Math.pow(10d,d1);
+				result = Math.floor(d0 * multi) / multi;
+				checkValue(result);
+			}catch (EvaluationException e) {
+				return e.getErrorEval();
+			}
+			return new NumberEval(result);
+		}
+	};
 
 	/* -------------------------------------------------------------------------- */
 

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/TextFunction.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/TextFunction.java?rev=937652&r1=937651&r2=937652&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/TextFunction.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/TextFunction.java Sat Apr 24 17:17:20 2010
@@ -17,6 +17,12 @@
 
 package org.apache.poi.hssf.record.formula.functions;
 
+import java.text.DateFormat;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
 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.EvaluationException;
@@ -28,6 +34,7 @@ import org.apache.poi.hssf.record.formul
 /**
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
  * @author Josh Micich
+ * @author Stephen Wolke (smwolke at geistig.com)
  */
 public abstract class TextFunction implements Function {
 
@@ -41,6 +48,11 @@ public abstract class TextFunction imple
 		ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
 		return OperandResolver.coerceValueToInt(ve);
 	}
+	
+	protected static final double evaluateDoubleArg(ValueEval arg, int srcCellRow, int srcCellCol) throws EvaluationException {
+		ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+		return OperandResolver.coerceValueToDouble(ve);
+	}
 
 	public final ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
 		try {
@@ -206,6 +218,86 @@ public abstract class TextFunction imple
 		}
 	};
 
+	/**
+	 * An implementation of the TEXT function<br/>
+	 * TEXT returns a number value formatted with the given
+	 * number formatting string. This function is not a complete implementation of
+	 * the Excel function.  This function implements decimal formatting
+	 * with the Java class DecimalFormat.  For date formatting this function uses
+	 * the SimpleDateFormat class.<p/>
+	 *
+	 * <b>Syntax<b>:<br/> <b>TEXT</b>(<b>value</b>, <b>format_text</b>)<br/>
+	 *
+	 */
+	public static final Function TEXT = new Fixed2ArgFunction() {
+
+		public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
+			double s0;
+			String s1;
+			try {
+				s0 = evaluateDoubleArg(arg0, srcRowIndex, srcColumnIndex);
+				s1 = evaluateStringArg(arg1, srcRowIndex, srcColumnIndex);
+			} catch (EvaluationException e) {
+				return e.getErrorEval();
+			}
+			if (s1.matches("[\\d,\\#,\\.,\\$,\\,]+")) {
+			NumberFormat formatter = new DecimalFormat(s1);
+			return new StringEval(formatter.format(s0));
+			} else if (s1.indexOf("/") == s1.lastIndexOf("/") && s1.indexOf("/") >=0 && !s1.contains("-")) {
+				double wholePart = Math.floor(s0);
+				double decPart = s0 - wholePart;
+				if (wholePart * decPart == 0) {
+					return new StringEval("0");
+				}
+				String[] parts = s1.split(" ");
+				String[] fractParts;
+				if (parts.length == 2) {
+					fractParts = parts[1].split("/");
+				} else {
+					fractParts = s1.split("/");
+				}
+
+				if (fractParts.length == 2) {
+					double minVal = 1.0;
+					double currDenom = Math.pow(10 ,  fractParts[1].length()) - 1d;
+					double currNeum = 0;
+					for (int i = (int)(Math.pow(10,  fractParts[1].length())- 1d); i > 0; i--) {
+						for(int i2 = (int)(Math.pow(10,  fractParts[1].length())- 1d); i2 > 0; i2--){
+							if (minVal >=  Math.abs((double)i2/(double)i - decPart)) {
+								currDenom = i;
+								currNeum = i2;
+								minVal = Math.abs((double)i2/(double)i  - decPart);
+							}
+						}
+					}
+					NumberFormat neumFormatter = new DecimalFormat(fractParts[0]);
+					NumberFormat denomFormatter = new DecimalFormat(fractParts[1]);
+					if (parts.length == 2) {
+						NumberFormat wholeFormatter = new DecimalFormat(parts[0]);
+						String result = wholeFormatter.format(wholePart) + " " + neumFormatter.format(currNeum) + "/" + denomFormatter.format(currDenom);
+						return new StringEval(result);
+					} else {
+						String result = neumFormatter.format(currNeum + (currDenom * wholePart)) + "/" + denomFormatter.format(currDenom);
+						return new StringEval(result);
+					}
+				} else {
+					return ErrorEval.VALUE_INVALID;
+				}
+			} else {
+				try {
+					DateFormat dateFormatter = new SimpleDateFormat(s1);
+					Calendar cal = new GregorianCalendar(1899, 11, 30, 0, 0, 0);
+					cal.add(Calendar.DATE, (int)Math.floor(s0));
+					double dayFraction = s0 - Math.floor(s0);
+					cal.add(Calendar.MILLISECOND, (int) Math.round(dayFraction * 24 * 60 * 60 * 1000));
+					return new StringEval(dateFormatter.format(cal.getTime()));
+				} catch (Exception e) {
+					return ErrorEval.VALUE_INVALID;
+				}
+			}
+		}
+	};
+	
 	private static final class SearchFind extends Var2or3ArgFunction {
 
 		private final boolean _isCaseSensitive;

Added: poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/TestText.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/TestText.java?rev=937652&view=auto
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/TestText.java (added)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/TestText.java Sat Apr 24 17:17:20 2010
@@ -0,0 +1,105 @@
+/* ====================================================================
+   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 junit.framework.TestCase;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.record.formula.eval.StringEval;
+
+/**
+ * Test case for TEXT()
+ *
+ * @author Stephen Wolke (smwolke at geistig.com)
+ */
+public final class TestText extends TestCase {
+	private static final TextFunction T = null;
+	
+	public void testTextWithStringFirstArg() {
+
+		ValueEval strArg = new StringEval("abc");
+		ValueEval formatArg = new StringEval("abc");
+		ValueEval[] args = { strArg, formatArg };
+		ValueEval result = T.TEXT.evaluate(args, -1, (short)-1);
+		assertEquals(ErrorEval.VALUE_INVALID, result);
+	}
+	
+	public void testTextWithDeciamlFormatSecondArg() {
+
+		ValueEval numArg = new NumberEval(321321.321);
+		ValueEval formatArg = new StringEval("#,###.00000");
+		ValueEval[] args = { numArg, formatArg };
+		ValueEval result = T.TEXT.evaluate(args, -1, (short)-1);
+		ValueEval testResult = new StringEval("321,321.32100");
+		assertEquals(testResult.toString(), result.toString());
+		numArg = new NumberEval(321.321);
+		formatArg = new StringEval("00000.00000");
+		args[0] = numArg; 
+		args[1] = formatArg; 
+		result = T.TEXT.evaluate(args, -1, (short)-1);
+		testResult = new StringEval("00321.32100");
+		assertEquals(testResult.toString(), result.toString());
+		
+		formatArg = new StringEval("$#.#");
+		args[1] = formatArg; 
+		result = T.TEXT.evaluate(args, -1, (short)-1);
+		testResult = new StringEval("$321.3");
+		assertEquals(testResult.toString(), result.toString());
+	}
+	
+	public void testTextWithFractionFormatSecondArg() {
+
+		ValueEval numArg = new NumberEval(321.321);
+		ValueEval formatArg = new StringEval("# #/#");
+		ValueEval[] args = { numArg, formatArg };
+		ValueEval result = T.TEXT.evaluate(args, -1, (short)-1);
+		ValueEval testResult = new StringEval("321 1/3");
+		assertEquals(testResult.toString(), result.toString());
+		
+		formatArg = new StringEval("# #/##");
+		args[1] = formatArg; 
+		result = T.TEXT.evaluate(args, -1, (short)-1);
+		testResult = new StringEval("321 26/81");
+		assertEquals(testResult.toString(), result.toString());
+		
+		formatArg = new StringEval("#/##");
+		args[1] = formatArg; 
+		result = T.TEXT.evaluate(args, -1, (short)-1);
+		testResult = new StringEval("26027/81");
+		assertEquals(testResult.toString(), result.toString());
+	}
+	
+	public void testTextWithDateFormatSecondArg() {
+
+		ValueEval numArg = new NumberEval(321.321);
+		ValueEval formatArg = new StringEval("dd:MM:yyyy hh:mm:ss");
+		ValueEval[] args = { numArg, formatArg };
+		ValueEval result = T.TEXT.evaluate(args, -1, (short)-1);
+		ValueEval testResult = new StringEval("16:11:1900 07:42:14");
+		assertEquals(testResult.toString(), result.toString());
+		
+		formatArg = new StringEval("MMMM dd, yyyy");
+		args[1] = formatArg; 
+		result = T.TEXT.evaluate(args, -1, (short)-1);
+		testResult = new StringEval("November 16, 1900");
+		assertEquals(testResult.toString(), result.toString());
+	}
+	
+	
+}

Added: poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTrunc.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTrunc.java?rev=937652&view=auto
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTrunc.java (added)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/TestTrunc.java Sat Apr 24 17:17:20 2010
@@ -0,0 +1,59 @@
+/* ====================================================================
+   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.ValueEval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.StringEval;
+
+/**
+ * Test case for TRUNC()
+ *
+ * @author Stephen Wolke (smwolke at geistig.com)
+ */
+public final class TestTrunc extends AbstractNumericTestCase {
+	private static final NumericFunction F = null;
+	public void testTruncWithStringArg() {
+
+		ValueEval strArg = new StringEval("abc");
+		ValueEval[] args = { strArg, new NumberEval(2) };
+		ValueEval result = F.TRUNC.evaluate(args, -1, (short)-1);
+		assertEquals(ErrorEval.VALUE_INVALID, result);
+	}
+
+	public void testTruncWithWholeNumber() {
+		ValueEval[] args = { new NumberEval(200), new NumberEval(2) };
+		@SuppressWarnings("static-access")
+		ValueEval result = F.TRUNC.evaluate(args, -1, (short)-1);
+		assertEquals("TRUNC", (new NumberEval(200d)).getNumberValue(), ((NumberEval)result).getNumberValue());
+	}
+	
+	public void testTruncWithDecimalNumber() {
+		ValueEval[] args = { new NumberEval(2.612777), new NumberEval(3) };
+		@SuppressWarnings("static-access")
+		ValueEval result = F.TRUNC.evaluate(args, -1, (short)-1);
+		assertEquals("TRUNC", (new NumberEval(2.612d)).getNumberValue(), ((NumberEval)result).getNumberValue());
+	}
+	
+	public void testTruncWithDecimalNumberOneArg() {
+		ValueEval[] args = { new NumberEval(2.612777) };
+		ValueEval result = F.TRUNC.evaluate(args, -1, (short)-1);
+		assertEquals("TRUNC", (new NumberEval(2d)).getNumberValue(), ((NumberEval)result).getNumberValue());
+	}
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org