mirror of https://github.com/apache/poi.git
fixed evaluation of blank cells in COUNTIF, see Bugzilla 51498
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1243054 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
5b291578bc
commit
1d8365e7a3
|
@ -34,6 +34,7 @@
|
||||||
|
|
||||||
<changes>
|
<changes>
|
||||||
<release version="3.8-beta6" date="2012-??-??">
|
<release version="3.8-beta6" date="2012-??-??">
|
||||||
|
<action dev="poi-developers" type="fix">51498 - fixed evaluation of blank cells in COUNTIF</action>
|
||||||
<action dev="poi-developers" type="add">52576 - support changing external file references in HSSFWorkbook</action>
|
<action dev="poi-developers" type="add">52576 - support changing external file references in HSSFWorkbook</action>
|
||||||
<action dev="poi-developers" type="add">49896 - support external references in FormulaRenderer</action>
|
<action dev="poi-developers" type="add">49896 - support external references in FormulaRenderer</action>
|
||||||
<action dev="poi-developers" type="fix">52527 - avoid exception when matching shared formula records in HSSF</action>
|
<action dev="poi-developers" type="fix">52527 - avoid exception when matching shared formula records in HSSF</action>
|
||||||
|
|
|
@ -217,6 +217,14 @@ public final class Countif extends Fixed2ArgFunction {
|
||||||
} else if((x instanceof NumberEval)) {
|
} else if((x instanceof NumberEval)) {
|
||||||
NumberEval ne = (NumberEval) x;
|
NumberEval ne = (NumberEval) x;
|
||||||
testValue = ne.getNumberValue();
|
testValue = ne.getNumberValue();
|
||||||
|
} else if((x instanceof BlankEval)) {
|
||||||
|
switch (getCode()) {
|
||||||
|
case CmpOp.NE:
|
||||||
|
// Excel counts blank values in range as not equal to any value. See Bugzilla 51498
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -258,7 +266,23 @@ public final class Countif extends Fixed2ArgFunction {
|
||||||
} else if((x instanceof BoolEval)) {
|
} else if((x instanceof BoolEval)) {
|
||||||
BoolEval be = (BoolEval) x;
|
BoolEval be = (BoolEval) x;
|
||||||
testValue = boolToInt(be.getBooleanValue());
|
testValue = boolToInt(be.getBooleanValue());
|
||||||
} else {
|
} else if((x instanceof BlankEval)) {
|
||||||
|
switch (getCode()) {
|
||||||
|
case CmpOp.NE:
|
||||||
|
// Excel counts blank values in range as not equal to any value. See Bugzilla 51498
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if((x instanceof NumberEval)) {
|
||||||
|
switch (getCode()) {
|
||||||
|
case CmpOp.NE:
|
||||||
|
// not-equals comparison of a number to boolean always returnes false
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return evaluate(testValue - _value);
|
return evaluate(testValue - _value);
|
||||||
|
@ -318,6 +342,10 @@ public final class Countif extends Fixed2ArgFunction {
|
||||||
case CmpOp.NONE:
|
case CmpOp.NONE:
|
||||||
case CmpOp.EQ:
|
case CmpOp.EQ:
|
||||||
return _value.length() == 0;
|
return _value.length() == 0;
|
||||||
|
case CmpOp.NE:
|
||||||
|
// pred '<>' matches empty string but not blank cell
|
||||||
|
// pred '<>ABC' matches blank and 'not ABC'
|
||||||
|
return _value.length() != 0;
|
||||||
}
|
}
|
||||||
// no other criteria matches a blank cell
|
// no other criteria matches a blank cell
|
||||||
return false;
|
return false;
|
||||||
|
@ -342,7 +370,9 @@ public final class Countif extends Fixed2ArgFunction {
|
||||||
if (_pattern != null) {
|
if (_pattern != null) {
|
||||||
return evaluate(_pattern.matcher(testedValue).matches());
|
return evaluate(_pattern.matcher(testedValue).matches());
|
||||||
}
|
}
|
||||||
return evaluate(testedValue.compareTo(_value));
|
// String criteria in COUNTIF are case insensitive:
|
||||||
|
// for example, the string "apples" and the string "APPLES" will match the same cells.
|
||||||
|
return evaluate(testedValue.compareToIgnoreCase(_value));
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Translates Excel countif wildcard strings into java regex strings
|
* Translates Excel countif wildcard strings into java regex strings
|
||||||
|
@ -394,7 +424,7 @@ public final class Countif extends Fixed2ArgFunction {
|
||||||
sb.append(ch);
|
sb.append(ch);
|
||||||
}
|
}
|
||||||
if (hasWildCard) {
|
if (hasWildCard) {
|
||||||
return Pattern.compile(sb.toString());
|
return Pattern.compile(sb.toString(), Pattern.CASE_INSENSITIVE);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2220,7 +2220,9 @@ if(1==2) {
|
||||||
public void test49896() {
|
public void test49896() {
|
||||||
HSSFWorkbook wb = openSample("49896.xls");
|
HSSFWorkbook wb = openSample("49896.xls");
|
||||||
HSSFCell cell = wb.getSheetAt(0).getRow(1).getCell(1);
|
HSSFCell cell = wb.getSheetAt(0).getRow(1).getCell(1);
|
||||||
assertEquals("VLOOKUP(A2,'[C:Documents and Settings/Yegor/My Documents/csco.xls]Sheet1'!$A$2:$B$3,2,FALSE)",
|
String PATH_SEPARATOR = System.getProperty("file.separator");
|
||||||
|
assertEquals("VLOOKUP(A2,'[C:Documents and Settings" + PATH_SEPARATOR+"Yegor"+PATH_SEPARATOR
|
||||||
|
+"My Documents"+PATH_SEPARATOR+"csco.xls]Sheet1'!$A$2:$B$3,2,FALSE)",
|
||||||
cell.getCellFormula());
|
cell.getCellFormula());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||||
import org.apache.poi.ss.usermodel.CellValue;
|
import org.apache.poi.ss.usermodel.CellValue;
|
||||||
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
import org.apache.poi.ss.usermodel.FormulaEvaluator;
|
||||||
|
import org.apache.poi.ss.util.CellReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test cases for COUNT(), COUNTA() COUNTIF(), COUNTBLANK()
|
* Test cases for COUNT(), COUNTA() COUNTIF(), COUNTBLANK()
|
||||||
|
@ -196,6 +197,27 @@ public final class TestCountFuncs extends TestCase {
|
||||||
confirmCountIf(4, range, new StringEval("<>111"));
|
confirmCountIf(4, range, new StringEval("<>111"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String criteria in COUNTIF are case insensitive;
|
||||||
|
* for example, the string "apples" and the string "APPLES" will match the same cells.
|
||||||
|
*/
|
||||||
|
public void testCaseInsensitiveStringComparison() {
|
||||||
|
AreaEval range;
|
||||||
|
ValueEval[] values;
|
||||||
|
|
||||||
|
values = new ValueEval[] {
|
||||||
|
new StringEval("no"),
|
||||||
|
new StringEval("NO"),
|
||||||
|
new StringEval("No"),
|
||||||
|
new StringEval("Yes")
|
||||||
|
};
|
||||||
|
|
||||||
|
range = EvalFactory.createAreaEval("A1:A4", values);
|
||||||
|
confirmCountIf(3, range, new StringEval("no"));
|
||||||
|
confirmCountIf(3, range, new StringEval("NO"));
|
||||||
|
confirmCountIf(3, range, new StringEval("No"));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* special case where the criteria argument is a cell reference
|
* special case where the criteria argument is a cell reference
|
||||||
*/
|
*/
|
||||||
|
@ -365,27 +387,48 @@ public final class TestCountFuncs extends TestCase {
|
||||||
* Bug #51498 - Check that CountIf behaves correctly for GTE, LTE
|
* Bug #51498 - Check that CountIf behaves correctly for GTE, LTE
|
||||||
* and NEQ cases
|
* and NEQ cases
|
||||||
*/
|
*/
|
||||||
public void testCountifLTEGTE() throws Exception {
|
public void testCountifBug51498() throws Exception {
|
||||||
final int REF_COL = 4;
|
final int REF_COL = 4;
|
||||||
final int EVAL_COL = 3;
|
final int EVAL_COL = 3;
|
||||||
|
|
||||||
// Note - POI currently agrees with OpenOffice on certain blank cell cases,
|
HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook("51498.xls");
|
||||||
// while Excel can differ. This is the list of checks to skip
|
|
||||||
List<Integer> skipRowsPendingExcelVsOpenOffice = Arrays.asList(
|
|
||||||
new Integer[] {3});
|
|
||||||
|
|
||||||
HSSFWorkbook workbook = HSSFTestDataSamples.openSampleWorkbook("51498.xls");
|
|
||||||
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
|
FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
|
||||||
HSSFSheet sheet = workbook.getSheetAt(0);
|
HSSFSheet sheet = workbook.getSheetAt(0);
|
||||||
for (int i = 0; i < 8; i++) {
|
|
||||||
if (skipRowsPendingExcelVsOpenOffice.contains(i)) {
|
// numeric criteria
|
||||||
// Skip the check for now
|
for (int i = 0; i < 8; i++) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
CellValue expected = evaluator.evaluate(sheet.getRow(i).getCell(REF_COL));
|
CellValue expected = evaluator.evaluate(sheet.getRow(i).getCell(REF_COL));
|
||||||
CellValue actual = evaluator.evaluate(sheet.getRow(i).getCell(EVAL_COL));
|
CellValue actual = evaluator.evaluate(sheet.getRow(i).getCell(EVAL_COL));
|
||||||
assertEquals(expected.formatAsString(), actual.formatAsString());
|
assertEquals(expected.formatAsString(), actual.formatAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// boolean criteria
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
HSSFCell cellFmla = sheet.getRow(i).getCell(8);
|
||||||
|
HSSFCell cellRef = sheet.getRow(i).getCell(9);
|
||||||
|
|
||||||
|
double expectedValue = cellRef.getNumericCellValue();
|
||||||
|
double actualValue = evaluator.evaluate(cellFmla).getNumberValue();
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"Problem with a formula at " +
|
||||||
|
new CellReference(cellFmla).formatAsString() + "[" + cellFmla.getCellFormula()+"] ",
|
||||||
|
expectedValue, actualValue, 0.0001);
|
||||||
|
}
|
||||||
|
|
||||||
|
// string criteria
|
||||||
|
for (int i = 1; i < 9; i++) {
|
||||||
|
HSSFCell cellFmla = sheet.getRow(i).getCell(13);
|
||||||
|
HSSFCell cellRef = sheet.getRow(i).getCell(14);
|
||||||
|
|
||||||
|
double expectedValue = cellRef.getNumericCellValue();
|
||||||
|
double actualValue = evaluator.evaluate(cellFmla).getNumberValue();
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"Problem with a formula at " +
|
||||||
|
new CellReference(cellFmla).formatAsString() + "[" + cellFmla.getCellFormula()+"] ",
|
||||||
|
expectedValue, actualValue, 0.0001);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testWildCards() {
|
public void testWildCards() {
|
||||||
|
@ -456,6 +499,53 @@ public final class TestCountFuncs extends TestCase {
|
||||||
testCountFunctionFromSpreadsheet("countifExamples.xls", 1, 2, 3, "countif");
|
testCountFunctionFromSpreadsheet("countifExamples.xls", 1, 2, 3, "countif");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two COUNTIF examples taken from
|
||||||
|
* http://office.microsoft.com/en-us/excel-help/countif-function-HP010069840.aspx?CTT=5&origin=HA010277524
|
||||||
|
*/
|
||||||
|
public void testCountifExamples() {
|
||||||
|
HSSFWorkbook wb = HSSFTestDataSamples.openSampleWorkbook("countifExamples.xls");
|
||||||
|
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
|
||||||
|
|
||||||
|
HSSFSheet sheet1 = wb.getSheet("MSDN Example 1");
|
||||||
|
for (int rowIx=7; rowIx<=12; rowIx++) {
|
||||||
|
HSSFRow row = sheet1.getRow(rowIx-1);
|
||||||
|
HSSFCell cellA = row.getCell(0); // cell containing a formula with COUNTIF
|
||||||
|
assertEquals(HSSFCell.CELL_TYPE_FORMULA, cellA.getCellType());
|
||||||
|
HSSFCell cellC = row.getCell(2); // cell with a reference value
|
||||||
|
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cellC.getCellType());
|
||||||
|
|
||||||
|
CellValue cv = fe.evaluate(cellA);
|
||||||
|
double actualValue = cv.getNumberValue();
|
||||||
|
double expectedValue = cellC.getNumericCellValue();
|
||||||
|
assertEquals(
|
||||||
|
"Problem with a formula at " + new CellReference(cellA).formatAsString()
|
||||||
|
+ ": " + cellA.getCellFormula() + " :"
|
||||||
|
+ "Expected = (" + expectedValue + ") Actual=(" + actualValue + ") ",
|
||||||
|
expectedValue, actualValue, 0.0001);
|
||||||
|
}
|
||||||
|
|
||||||
|
HSSFSheet sheet2 = wb.getSheet("MSDN Example 2");
|
||||||
|
for (int rowIx=9; rowIx<=14; rowIx++) {
|
||||||
|
HSSFRow row = sheet2.getRow(rowIx-1);
|
||||||
|
HSSFCell cellA = row.getCell(0); // cell containing a formula with COUNTIF
|
||||||
|
assertEquals(HSSFCell.CELL_TYPE_FORMULA, cellA.getCellType());
|
||||||
|
HSSFCell cellC = row.getCell(2); // cell with a reference value
|
||||||
|
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cellC.getCellType());
|
||||||
|
|
||||||
|
CellValue cv = fe.evaluate(cellA);
|
||||||
|
double actualValue = cv.getNumberValue();
|
||||||
|
double expectedValue = cellC.getNumericCellValue();
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"Problem with a formula at " +
|
||||||
|
new CellReference(cellA).formatAsString() + "[" + cellA.getCellFormula()+"]: "
|
||||||
|
+ "Expected = (" + expectedValue + ") Actual=(" + actualValue + ") ",
|
||||||
|
expectedValue, actualValue, 0.0001);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void testCountBlankFromSpreadsheet() {
|
public void testCountBlankFromSpreadsheet() {
|
||||||
testCountFunctionFromSpreadsheet("countblankExamples.xls", 1, 3, 4, "countblank");
|
testCountFunctionFromSpreadsheet("countblankExamples.xls", 1, 3, 4, "countblank");
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue