You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by jo...@apache.org on 2008/10/27 19:16:45 UTC

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

Author: josh
Date: Mon Oct 27 11:16:44 2008
New Revision: 708262

URL: http://svn.apache.org/viewvc?rev=708262&view=rev
Log:
Bugzilla 46065 - added implementation for VALUE function

Added:
    poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/TestValue.java
Modified:
    poi/trunk/src/documentation/content/xdocs/changes.xml
    poi/trunk/src/documentation/content/xdocs/status.xml
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Value.java
    poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java

Modified: poi/trunk/src/documentation/content/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/changes.xml?rev=708262&r1=708261&r2=708262&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/changes.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/changes.xml Mon Oct 27 11:16:44 2008
@@ -37,6 +37,7 @@
 
 		<!-- Don't forget to update status.xml too! -->
         <release version="3.5-beta4" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="add">46065 - added implementation for VALUE function</action>
            <action dev="POI-DEVELOPERS" type="add">45966 - added implementation for FIND function</action>
            <action dev="POI-DEVELOPERS" type="fix">45778 - fixed ObjRecord to read ftLbsData properly</action>
            <action dev="POI-DEVELOPERS" type="fix">46053 - fixed evaluation cache dependency analysis when changing blank cells</action>

Modified: poi/trunk/src/documentation/content/xdocs/status.xml
URL: http://svn.apache.org/viewvc/poi/trunk/src/documentation/content/xdocs/status.xml?rev=708262&r1=708261&r2=708262&view=diff
==============================================================================
--- poi/trunk/src/documentation/content/xdocs/status.xml (original)
+++ poi/trunk/src/documentation/content/xdocs/status.xml Mon Oct 27 11:16:44 2008
@@ -34,6 +34,7 @@
 	<!-- Don't forget to update changes.xml too! -->
     <changes>
         <release version="3.5-beta4" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="add">46065 - added implementation for VALUE function</action>
            <action dev="POI-DEVELOPERS" type="add">45966 - added implementation for FIND function</action>
            <action dev="POI-DEVELOPERS" type="fix">45778 - fixed ObjRecord to read ftLbsData properly</action>
            <action dev="POI-DEVELOPERS" type="fix">46053 - fixed evaluation cache dependency analysis when changing blank cells</action>

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Value.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Value.java?rev=708262&r1=708261&r2=708262&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Value.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Value.java Mon Oct 27 11:16:44 2008
@@ -1,25 +1,188 @@
-/*
-* 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;
 
-public class Value extends NotImplementedFunction {
+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;
+
+/**
+ * Implementation for Excel VALUE() function.<p/>
+ * 
+ * <b>Syntax</b>:<br/> <b>VALUE</b>(<b>text</b>)<br/>
+ * 
+ * Converts the text argument to a number. Leading and/or trailing whitespace is
+ * ignored. Currency symbols and thousands separators are stripped out.
+ * Scientific notation is also supported. If the supplied text does not convert
+ * properly the result is <b>#VALUE!</b> error. Blank string converts to zero.
+ * 
+ * @author Josh Micich
+ */
+public final class Value implements Function {
+
+	/** "1,0000" is valid, "1,00" is not */
+	private static final int MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR = 4;
+	private static final Double ZERO = new Double(0.0);
+
+	public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
+		if (args.length != 1) {
+			return ErrorEval.VALUE_INVALID;
+		}
+		ValueEval veText;
+		try {
+			veText = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
+		} catch (EvaluationException e) {
+			return e.getErrorEval();
+		}
+		String strText = OperandResolver.coerceValueToString(veText);
+		Double result = convertTextToNumber(strText);
+		if (result == null) {
+			return ErrorEval.VALUE_INVALID;
+		}
+		return new NumberEval(result.doubleValue());
+	}
+
+	/**
+	 * TODO see if the same functionality is needed in {@link OperandResolver#parseDouble(String)} 
+	 * 
+	 * @return <code>null</code> if there is any problem converting the text
+	 */
+	private static Double convertTextToNumber(String strText) {
+		boolean foundCurrency = false;
+		boolean foundUnaryPlus = false;
+		boolean foundUnaryMinus = false;
+
+		int len = strText.length();
+		int i;
+		for (i = 0; i < len; i++) {
+			char ch = strText.charAt(i);
+			if (Character.isDigit(ch) || ch == '.') {
+				break;
+			}
+			switch (ch) {
+				case ' ':
+					// intervening spaces between '$', '-', '+' are OK
+					continue;
+				case '$':
+					if (foundCurrency) {
+						// only one currency symbols is allowed
+						return null;
+					}
+					foundCurrency = true;
+					continue;
+				case '+':
+					if (foundUnaryMinus || foundUnaryPlus) {
+						return null;
+					}
+					foundUnaryPlus = true;
+					continue;
+				case '-':
+					if (foundUnaryMinus || foundUnaryPlus) {
+						return null;
+					}
+					foundUnaryMinus = true;
+					continue;
+				default:
+					// all other characters are illegal
+					return null;
+			}
+		}
+		if (i >= len) {
+			// didn't find digits or '.'
+			if (foundCurrency || foundUnaryMinus || foundUnaryPlus) {
+				return null;
+			}
+			return ZERO;
+		}
+
+		// remove thousands separators
+
+		boolean foundDecimalPoint = false;
+		int lastThousandsSeparatorIndex = Short.MIN_VALUE;
 
+		StringBuffer sb = new StringBuffer(len);
+		for (; i < len; i++) {
+			char ch = strText.charAt(i);
+			if (Character.isDigit(ch)) {
+				sb.append(ch);
+				continue;
+			}
+			switch (ch) {
+				case ' ':
+					String remainingText = strText.substring(i);
+					if (remainingText.trim().length() > 0) {
+						// intervening spaces not allowed once the digits start
+						return null;
+					}
+					break;
+				case '.':
+					if (foundDecimalPoint) {
+						return null;
+					}
+					if (i - lastThousandsSeparatorIndex < MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR) {
+						return null;
+					}
+					foundDecimalPoint = true;
+					sb.append('.');
+					continue;
+				case ',':
+					if (foundDecimalPoint) {
+						// thousands separators not allowed after '.' or 'E'
+						return null;
+					}
+					int distanceBetweenThousandsSeparators = i - lastThousandsSeparatorIndex;
+					// as long as there are 3 or more digits between
+					if (distanceBetweenThousandsSeparators < MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR) {
+						return null;
+					}
+					lastThousandsSeparatorIndex = i;
+					// don't append ','
+					continue;
+	
+				case 'E':
+				case 'e':
+					if (i - lastThousandsSeparatorIndex < MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR) {
+						return null;
+					}
+					// append rest of strText and skip to end of loop
+					sb.append(strText.substring(i));
+					i = len;
+					break;
+				default:
+					// all other characters are illegal
+					return null;
+			}
+		}
+		if (!foundDecimalPoint) {
+			if (i - lastThousandsSeparatorIndex < MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR) {
+				return null;
+			}
+		}
+		double d;
+		try {
+			d = Double.parseDouble(sb.toString());
+		} catch (NumberFormatException e) {
+			// still a problem parsing the number - probably out of range
+			return null;
+		}
+		return new Double(foundUnaryMinus ? -d : d);
+	}
 }

Modified: poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java?rev=708262&r1=708261&r2=708262&view=diff
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java (original)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java Mon Oct 27 11:16:44 2008
@@ -50,6 +50,7 @@
 		result.addTestSuite(TestStatsLib.class);
 		result.addTestSuite(TestTFunc.class);
 		result.addTestSuite(TestTrim.class);
+		result.addTestSuite(TestValue.class);
 		result.addTestSuite(TestXYNumericFunction.class);
 		return result;
 	}

Added: poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/TestValue.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/TestValue.java?rev=708262&view=auto
==============================================================================
--- poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/TestValue.java (added)
+++ poi/trunk/src/testcases/org/apache/poi/hssf/record/formula/functions/TestValue.java Mon Oct 27 11:16:44 2008
@@ -0,0 +1,94 @@
+/* ====================================================================
+   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.Eval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.StringEval;
+
+/**
+ * Tests for {@link Value}
+ * 
+ * @author Josh Micich
+ */
+public final class TestValue extends TestCase {
+
+	private static Eval invokeValue(String strText) {
+		Eval[] args = new Eval[] { new StringEval(strText), };
+		return new Value().evaluate(args, -1, (short) -1);
+	}
+
+	private static void confirmValue(String strText, double expected) {
+		Eval result = invokeValue(strText);
+		assertEquals(NumberEval.class, result.getClass());
+		assertEquals(expected, ((NumberEval) result).getNumberValue(), 0.0);
+	}
+
+	private static void confirmValueError(String strText) {
+		Eval result = invokeValue(strText);
+		assertEquals(ErrorEval.class, result.getClass());
+		assertEquals(ErrorEval.VALUE_INVALID, result);
+	}
+
+	public void testBasic() {
+
+		confirmValue("100", 100);
+		confirmValue("-2.3", -2.3);
+		confirmValue(".5", 0.5);
+		confirmValue(".5e2", 50);
+		confirmValue(".5e-2", 0.005);
+		confirmValue(".5e+2", 50);
+		confirmValue("+5", 5);
+		confirmValue("$1,000", 1000);
+		confirmValue("100.5e1", 1005);
+		confirmValue("1,0000", 10000);
+		confirmValue("1,000,0000", 10000000);
+		confirmValue("1,000,0000,00000", 1000000000000.0);
+		confirmValue(" 100 ", 100);
+		confirmValue(" + 100", 100);
+		confirmValue("10000", 10000);
+		confirmValue("$-5", -5);
+		confirmValue("$.5", 0.5);
+		confirmValue("123e+5", 12300000);
+		confirmValue("1,000e2", 100000);
+		confirmValue("$10e2", 1000);
+		confirmValue("$1,000e2", 100000);
+	}
+
+	public void testErrors() {
+		confirmValueError("1+1");
+		confirmValueError("1 1");
+		confirmValueError("1,00.0");
+		confirmValueError("1,00");
+		confirmValueError("$1,00.5e1");
+		confirmValueError("1,00.5e1");
+		confirmValueError("1,0,000");
+		confirmValueError("1,00,000");
+		confirmValueError("++100");
+		confirmValueError("$$5");
+		confirmValueError("-");
+		confirmValueError("+");
+		confirmValueError("$");
+		confirmValueError(",300");
+		confirmValueError("0.233,4");
+		confirmValueError("1e2.5");
+	}
+}



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