diff --git a/src/documentation/content/xdocs/changes.xml b/src/documentation/content/xdocs/changes.xml index 6a30338359..6a37e74f9a 100644 --- a/src/documentation/content/xdocs/changes.xml +++ b/src/documentation/content/xdocs/changes.xml @@ -37,6 +37,7 @@ + 45966 - added implementation for FIND function 45778 - fixed ObjRecord to read ftLbsData properly 46053 - fixed evaluation cache dependency analysis when changing blank cells diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index 31ac7e337d..5dc90fdea4 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 45966 - added implementation for FIND function 45778 - fixed ObjRecord to read ftLbsData properly 46053 - fixed evaluation cache dependency analysis when changing blank cells diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Find.java b/src/java/org/apache/poi/hssf/record/formula/functions/Find.java index 7bd11ecf34..5621eb5cea 100644 --- a/src/java/org/apache/poi/hssf/record/formula/functions/Find.java +++ b/src/java/org/apache/poi/hssf/record/formula/functions/Find.java @@ -1,25 +1,65 @@ -/* -* 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 Find extends NotImplementedFunction { +import org.apache.poi.hssf.record.formula.eval.Eval; +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.EvaluationException; +/** + * Implementation of the FIND() function.

+ * + * Syntax:
+ * FIND(find_text, within_text, start_num)

+ * + * FIND returns the character position of the first occurrence of find_text inside + * within_text. The third parameter, start_num, is optional (default=1) + * and specifies where to start searching from. Character positions are 1-based.

+ * + * @author Torstein Tauno Svendsen (torstei@officenet.no) + */ +public class Find extends TextFunction { + + protected ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol) + throws EvaluationException { + + int nArgs = args.length; + if (nArgs < 2 || nArgs > 3) { + return ErrorEval.VALUE_INVALID; + } + String needle = evaluateStringArg(args[0], srcCellRow, srcCellCol); + String haystack = evaluateStringArg(args[1], srcCellRow, srcCellCol); + int startpos; + if (nArgs == 3) { + startpos = evaluateIntArg(args[2], srcCellRow, srcCellCol); + if (startpos <= 0) { + return ErrorEval.VALUE_INVALID; + } + startpos--; // convert 1-based to zero based + } else { + startpos = 0; + } + int result = haystack.indexOf(needle, startpos); + if (result == -1) { + return ErrorEval.VALUE_INVALID; + } + return new NumberEval(result + 1); + } } diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java index c57c40b62a..df16d208cc 100755 --- a/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java +++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/AllIndividualFunctionEvaluationTests.java @@ -32,6 +32,7 @@ public final class AllIndividualFunctionEvaluationTests { result.addTestSuite(TestAverage.class); result.addTestSuite(TestCountFuncs.class); result.addTestSuite(TestDate.class); + result.addTestSuite(TestFind.class); result.addTestSuite(TestFinanceLib.class); result.addTestSuite(TestIndex.class); result.addTestSuite(TestIndexFunctionFromSpreadsheet.class); diff --git a/src/testcases/org/apache/poi/hssf/record/formula/functions/TestFind.java b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestFind.java new file mode 100644 index 0000000000..11013f47d5 --- /dev/null +++ b/src/testcases/org/apache/poi/hssf/record/formula/functions/TestFind.java @@ -0,0 +1,76 @@ +/* ==================================================================== + 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.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFErrorConstants; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue; + +/** + * Tests for {@link Find} + * + * @author Torstein Svendsen (torstei@officenet.no) + */ +public final class TestFind extends TestCase { + + public void testFind() { + HSSFWorkbook wb = new HSSFWorkbook(); + HSSFCell cell = wb.createSheet().createRow(0).createCell(0); + + HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); + + confirmResult(fe, cell, "find(\"h\", \"haystack\")", 1); + confirmResult(fe, cell, "find(\"a\", \"haystack\",2)", 2); + confirmResult(fe, cell, "find(\"a\", \"haystack\",3)", 6); + + // number args converted to text + confirmResult(fe, cell, "find(7, 32768)", 3); + confirmResult(fe, cell, "find(\"34\", 1341235233412, 3)", 10); + confirmResult(fe, cell, "find(5, 87654)", 4); + + // Errors + confirmError(fe, cell, "find(\"n\", \"haystack\")", HSSFErrorConstants.ERROR_VALUE); + confirmError(fe, cell, "find(\"k\", \"haystack\",9)", HSSFErrorConstants.ERROR_VALUE); + confirmError(fe, cell, "find(\"k\", \"haystack\",#REF!)", HSSFErrorConstants.ERROR_REF); + confirmError(fe, cell, "find(\"k\", \"haystack\",0)", HSSFErrorConstants.ERROR_VALUE); + confirmError(fe, cell, "find(#DIV/0!, #N/A, #REF!)", HSSFErrorConstants.ERROR_DIV_0); + confirmError(fe, cell, "find(2, #N/A, #REF!)", HSSFErrorConstants.ERROR_NA); + } + + private static void confirmResult(HSSFFormulaEvaluator fe, HSSFCell cell, String formulaText, + int expectedResult) { + cell.setCellFormula(formulaText); + fe.notifyUpdateCell(cell); + CellValue result = fe.evaluate(cell); + assertEquals(result.getCellType(), HSSFCell.CELL_TYPE_NUMERIC); + assertEquals(expectedResult, result.getNumberValue(), 0.0); + } + + private static void confirmError(HSSFFormulaEvaluator fe, HSSFCell cell, String formulaText, + int expectedErrorCode) { + cell.setCellFormula(formulaText); + fe.notifyUpdateCell(cell); + CellValue result = fe.evaluate(cell); + assertEquals(result.getCellType(), HSSFCell.CELL_TYPE_ERROR); + assertEquals(expectedErrorCode, result.getErrorValue()); + } +}