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());
+ }
+}