--- src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java (revision 829277)
+++ src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java (working copy)
@@ -203,6 +203,7 @@
retval[345] = new Sumif();
retval[346] = new Countif();
+ retval[347] = new Countblank();
retval[359] = new Hyperlink();
--- src/java/org/apache/poi/hssf/record/formula/functions/Countblank.java (revision 0)
+++ src/java/org/apache/poi/hssf/record/formula/functions/Countblank.java (revision 0)
@@ -0,0 +1,73 @@
+/* ====================================================================
+ 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.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.BlankEval;
+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.RefEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.record.formula.functions.CountUtils.I_MatchPredicate;
+
+/**
+ * Implementation for the function COUNTBLANK
+ *
+ * Syntax: COUNTBLANK ( range )
+ *
+ * range | is the range of cells to count blanks |
+ *
+ *
+ *
+ * @author Mads Mohr Christensen
+ */
+public final class Countblank implements Function {
+
+ public ValueEval evaluate(ValueEval[] args, int srcRowIndex, short srcColumnIndex) {
+ switch(args.length) {
+ case 1:
+ // expected
+ break;
+ default:
+ // TODO - it doesn't seem to be possible to enter COUNTBLANK() into Excel with the wrong arg count
+ // perhaps this should be an exception
+ return ErrorEval.VALUE_INVALID;
+ }
+
+ double result;
+ if (args[0] instanceof RefEval) {
+ result = CountUtils.countMatchingCell((RefEval) args[0], predicate);
+ } else if (args[0] instanceof AreaEval) {
+ result = CountUtils.countMatchingCellsInArea((AreaEval) args[0], predicate);
+ } else {
+ throw new IllegalArgumentException("Bad range arg type (" + args[0].getClass().getName() + ")");
+ }
+ return new NumberEval(result);
+ }
+
+ private static final I_MatchPredicate predicate = new I_MatchPredicate() {
+
+ public boolean matches(ValueEval valueEval) {
+ if(valueEval == BlankEval.INSTANCE) {
+ return true;
+ }
+ // Note - only BlankEval counts
+ return false;
+ }
+ };
+}
--- src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java (revision 829277)
+++ src/testcases/org/apache/poi/hssf/record/formula/functions/TestCountFuncs.java (working copy)
@@ -45,7 +45,35 @@
public final class TestCountFuncs extends TestCase {
private static final String NULL = null;
+
+ public void testCountBlank() {
+ AreaEval range;
+ ValueEval[] values;
+
+ values = new ValueEval[] {
+ new NumberEval(0),
+ new StringEval(""), // note - does not match blank
+ BoolEval.TRUE,
+ BoolEval.FALSE,
+ ErrorEval.DIV_ZERO,
+ BlankEval.INSTANCE,
+ };
+ range = EvalFactory.createAreaEval("A1:B3", values);
+ confirmCountBlank(1, range);
+
+ values = new ValueEval[] {
+ new NumberEval(0),
+ new StringEval(""), // note - does not match blank
+ BlankEval.INSTANCE,
+ BoolEval.FALSE,
+ BoolEval.TRUE,
+ BlankEval.INSTANCE,
+ };
+ range = EvalFactory.createAreaEval("A1:B3", values);
+ confirmCountBlank(2, range);
+ }
+
public void testCountA() {
ValueEval[] args;
@@ -196,6 +224,12 @@
double result = NumericFunctionInvoker.invoke(new Countif(), args);
assertEquals(expected, result, 0);
}
+ private static void confirmCountBlank(int expected, AreaEval range) {
+
+ ValueEval[] args = { range };
+ double result = NumericFunctionInvoker.invoke(new Countblank(), args);
+ assertEquals(expected, result, 0);
+ }
private static I_MatchPredicate createCriteriaPredicate(ValueEval ev) {
return Countif.createCriteriaPredicate(ev, 0, 0);
@@ -418,4 +452,36 @@
throw new AssertionFailedError(failureCount + " countif evaluations failed. See stderr for more details");
}
}
+
+ public void testCounBlankFromSpreadsheet() {
+ final String FILE_NAME = "countblankExamples.xls";
+ final int START_ROW_IX = 1;
+ final int COL_IX_ACTUAL = 3;
+ final int COL_IX_EXPECTED = 4;
+
+ int failureCount = 0;
+ HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook(FILE_NAME);
+ HSSFSheet sheet = wb.getSheetAt(0);
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
+ int maxRow = sheet.getLastRowNum();
+ for (int rowIx=START_ROW_IX; rowIx 0) {
+ throw new AssertionFailedError(failureCount + " countblank evaluations failed. See stderr for more details");
+ }
+ }
}