Added implementation for TEXT() and TRUNC(), see Bugzilla 49025 and 49026
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@937652 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
2187e24118
commit
927e153c94
@ -34,6 +34,8 @@
|
|||||||
|
|
||||||
<changes>
|
<changes>
|
||||||
<release version="3.7-SNAPSHOT" date="2010-??-??">
|
<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">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">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>
|
<action dev="POI-DEVELOPERS" type="fix">49153 - Ensure that CTVectorVariant is included in poi-ooxml-schemas.jar</action>
|
||||||
|
@ -94,6 +94,7 @@ public final class FunctionEval {
|
|||||||
retval[37] = BooleanFunction.OR;
|
retval[37] = BooleanFunction.OR;
|
||||||
retval[38] = BooleanFunction.NOT;
|
retval[38] = BooleanFunction.NOT;
|
||||||
retval[39] = NumericFunction.MOD;
|
retval[39] = NumericFunction.MOD;
|
||||||
|
retval[48] = TextFunction.TEXT;
|
||||||
|
|
||||||
retval[56] = FinanceFunction.PV;
|
retval[56] = FinanceFunction.PV;
|
||||||
retval[57] = FinanceFunction.FV;
|
retval[57] = FinanceFunction.FV;
|
||||||
@ -152,7 +153,7 @@ public final class FunctionEval {
|
|||||||
retval[184] = NumericFunction.FACT;
|
retval[184] = NumericFunction.FACT;
|
||||||
|
|
||||||
retval[190] = LogicalFunction.ISNONTEXT;
|
retval[190] = LogicalFunction.ISNONTEXT;
|
||||||
|
retval[197] = NumericFunction.TRUNC;
|
||||||
retval[198] = LogicalFunction.ISLOGICAL;
|
retval[198] = LogicalFunction.ISLOGICAL;
|
||||||
|
|
||||||
retval[212] = NumericFunction.ROUNDUP;
|
retval[212] = NumericFunction.ROUNDUP;
|
||||||
|
@ -26,6 +26,7 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
|||||||
/**
|
/**
|
||||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||||
* @author Josh Micich
|
* @author Josh Micich
|
||||||
|
* @author Stephen Wolke (smwolke at geistig.com)
|
||||||
*/
|
*/
|
||||||
public abstract class NumericFunction implements Function {
|
public abstract class NumericFunction implements Function {
|
||||||
|
|
||||||
@ -321,6 +322,27 @@ public abstract class NumericFunction implements Function {
|
|||||||
return MathX.roundUp(d0, (int)d1);
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
@ -17,6 +17,12 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula.functions;
|
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.BoolEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.EvaluationException;
|
import org.apache.poi.hssf.record.formula.eval.EvaluationException;
|
||||||
@ -28,6 +34,7 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
|||||||
/**
|
/**
|
||||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||||
* @author Josh Micich
|
* @author Josh Micich
|
||||||
|
* @author Stephen Wolke (smwolke at geistig.com)
|
||||||
*/
|
*/
|
||||||
public abstract class TextFunction implements Function {
|
public abstract class TextFunction implements Function {
|
||||||
|
|
||||||
@ -41,6 +48,11 @@ public abstract class TextFunction implements Function {
|
|||||||
ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
|
ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
|
||||||
return OperandResolver.coerceValueToInt(ve);
|
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) {
|
public final ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
|
||||||
try {
|
try {
|
||||||
@ -206,6 +218,86 @@ public abstract class TextFunction implements Function {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 static final class SearchFind extends Var2or3ArgFunction {
|
||||||
|
|
||||||
private final boolean _isCaseSensitive;
|
private final boolean _isCaseSensitive;
|
||||||
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user