diff --git a/src/java/org/apache/poi/hssf/record/NameRecord.java b/src/java/org/apache/poi/hssf/record/NameRecord.java
index b2cc897b5..b12a3c6ad 100644
--- a/src/java/org/apache/poi/hssf/record/NameRecord.java
+++ b/src/java/org/apache/poi/hssf/record/NameRecord.java
@@ -487,7 +487,7 @@ public final class NameRecord extends Record {
}
private static Ptg createNewPtg(){
- return new Area3DPtg("A1", 0); // TODO - change to not be partially initialised
+ return new Area3DPtg("A1:A1", 0); // TODO - change to not be partially initialised
}
/** gets the reference , the area only (range)
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java b/src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java
index 8604eadc3..e6efaaee4 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java
@@ -60,8 +60,8 @@ public final class Hlookup implements Function {
AreaEval tableArray = LookupUtils.resolveTableArrayArg(args[1]);
boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcCellRow, srcCellCol);
int colIndex = LookupUtils.lookupIndexOfValue(lookupValue, LookupUtils.createRowVector(tableArray, 0), isRangeLookup);
- ValueEval veColIndex = OperandResolver.getSingleValue(args[2], srcCellRow, srcCellCol);
- int rowIndex = LookupUtils.resolveRowOrColIndexArg(veColIndex);
+ ValueEval veRowIndex = OperandResolver.getSingleValue(args[2], srcCellRow, srcCellCol);
+ int rowIndex = LookupUtils.resolveRowOrColIndexArg(veRowIndex);
ValueVector resultCol = createResultColumnVector(tableArray, rowIndex);
return resultCol.getItem(colIndex);
} catch (EvaluationException e) {
@@ -75,13 +75,13 @@ public final class Hlookup implements Function {
*
* @throws EvaluationException (#VALUE!) if colIndex is negative, (#REF!) if colIndex is too high
*/
- private ValueVector createResultColumnVector(AreaEval tableArray, int colIndex) throws EvaluationException {
- if(colIndex < 0) {
+ private ValueVector createResultColumnVector(AreaEval tableArray, int rowIndex) throws EvaluationException {
+ if(rowIndex < 0) {
throw EvaluationException.invalidValue();
}
- if(colIndex >= tableArray.getWidth()) {
+ if(rowIndex >= tableArray.getHeight()) {
throw EvaluationException.invalidRef();
}
- return LookupUtils.createRowVector(tableArray, colIndex);
+ return LookupUtils.createRowVector(tableArray, rowIndex);
}
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Index.java b/src/java/org/apache/poi/hssf/record/formula/functions/Index.java
index 3c93c0846..024bd7a05 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Index.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Index.java
@@ -90,9 +90,19 @@ public final class Index implements Function {
}
}
- private static ValueEval getValueFromArea(AreaEval ae, int rowIx, int columnIx) throws EvaluationException {
+ private static ValueEval getValueFromArea(AreaEval ae, int pRowIx, int pColumnIx) throws EvaluationException {
int width = ae.getWidth();
int height = ae.getHeight();
+ int rowIx;
+ int columnIx;
+ if (ae.isRow() && pColumnIx == 0 && pRowIx > 0) {
+ // TODO - explore all these special cases
+ rowIx = 0;
+ columnIx = pRowIx;
+ } else {
+ rowIx = pRowIx;
+ columnIx = pColumnIx;
+ }
// Slightly irregular logic for bounds checking errors
if (rowIx >= height || columnIx >= width) {
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java b/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java
index e6a3ec81c..972a60aaa 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java
@@ -17,6 +17,7 @@
package org.apache.poi.hssf.record.formula.functions;
+import org.apache.poi.hssf.record.NumberRecord;
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.BoolEval;
@@ -587,7 +588,9 @@ final class LookupUtils {
if (lookupValue instanceof BlankEval) {
// blank eval can never be found in a lookup array
- throw new EvaluationException(ErrorEval.NA);
+ //throw new EvaluationException(ErrorEval.NA);
+ // TODO - investigate this
+ return new NumberLookupComparer(NumberEval.ZERO);
}
if (lookupValue instanceof StringEval) {
return new StringLookupComparer((StringEval) lookupValue);
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Vlookup.java b/src/java/org/apache/poi/hssf/record/formula/functions/Vlookup.java
index 54f7d465e..f6b65f649 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Vlookup.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Vlookup.java
@@ -60,7 +60,16 @@ public final class Vlookup implements Function {
AreaEval tableArray = LookupUtils.resolveTableArrayArg(args[1]);
boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcCellRow, srcCellCol);
int rowIndex = LookupUtils.lookupIndexOfValue(lookupValue, LookupUtils.createColumnVector(tableArray, 0), isRangeLookup);
- ValueEval veColIndex = OperandResolver.getSingleValue(args[2], srcCellRow, srcCellCol);
+ ValueEval veColIndex;
+ try {
+ veColIndex = OperandResolver.getSingleValue(args[2], srcCellRow, srcCellCol);
+ } catch (EvaluationException e) {
+ // weird translation of errors for the third arg - needs investigation
+ if (e.getErrorEval() == ErrorEval.NA) {
+ return ErrorEval.REF_INVALID;
+ }
+ throw e;
+ }
int colIndex = LookupUtils.resolveRowOrColIndexArg(veColIndex);
ValueVector resultCol = createResultColumnVector(tableArray, colIndex);
return resultCol.getItem(rowIndex);
diff --git a/src/java/org/apache/poi/hssf/util/AreaReference.java b/src/java/org/apache/poi/hssf/util/AreaReference.java
index 99218222f..0319843d7 100644
--- a/src/java/org/apache/poi/hssf/util/AreaReference.java
+++ b/src/java/org/apache/poi/hssf/util/AreaReference.java
@@ -46,29 +46,59 @@ public final class AreaReference {
}
String[] parts = separateAreaRefs(reference);
-
- // Special handling for whole-column references
- if(parts.length == 2 && parts[0].length() == 1 &&
- parts[1].length() == 1 &&
- parts[0].charAt(0) >= 'A' && parts[0].charAt(0) <= 'Z' &&
- parts[1].charAt(0) >= 'A' && parts[1].charAt(0) <= 'Z') {
- // Represented internally as x$1 to x$65536
- // which is the maximum range of rows
- parts[0] = parts[0] + "$1";
- parts[1] = parts[1] + "$65536";
- }
-
- _firstCell = new CellReference(parts[0]);
-
- if(parts.length == 2) {
- _lastCell = new CellReference(parts[1]);
- _isSingleCell = false;
- } else {
+ String part0 = parts[0];
+ if (parts.length == 1) {
+ // TODO - probably shouldn't initialize area ref when text is really a cell ref
+ // Need to fix some named range stuff to get rid of this
+ _firstCell = new CellReference(part0);
+
_lastCell = _firstCell;
_isSingleCell = true;
+ return;
}
- }
+ if (parts.length != 2) {
+ throw new IllegalArgumentException("Bad area ref '" + reference + "'");
+ }
+
+ String part1 = parts[1];
+ if (isPlainColumn(part0)) {
+ if (!isPlainColumn(part1)) {
+ throw new RuntimeException("Bad area ref '" + reference + "'");
+ }
+ // Special handling for whole-column references
+ // Represented internally as x$1 to x$65536
+ // which is the maximum range of rows
+
+ boolean firstIsAbs = CellReference.isPartAbsolute(part0);
+ boolean lastIsAbs = CellReference.isPartAbsolute(part1);
+
+ int col0 = CellReference.convertColStringToIndex(part0);
+ int col1 = CellReference.convertColStringToIndex(part1);
+
+ _firstCell = new CellReference(0, col0, true, firstIsAbs);
+ _lastCell = new CellReference(0xFFFF, col1, true, lastIsAbs);
+ _isSingleCell = false;
+ // TODO - whole row refs
+ } else {
+ _firstCell = new CellReference(part0);
+ _lastCell = new CellReference(part1);
+ _isSingleCell = part0.equals(part1);
+ }
+ }
+ private boolean isPlainColumn(String refPart) {
+ for(int i=refPart.length()-1; i>=0; i--) {
+ int ch = refPart.charAt(i);
+ if (ch == '$' && i==0) {
+ continue;
+ }
+ if (ch < 'A' || ch > 'Z') {
+ return false;
+ }
+ }
+ return true;
+ }
+
/**
* Creates an area ref from a pair of Cell References.
*/
diff --git a/src/java/org/apache/poi/hssf/util/CellReference.java b/src/java/org/apache/poi/hssf/util/CellReference.java
index efbc37eff..4fe07a5a4 100644
--- a/src/java/org/apache/poi/hssf/util/CellReference.java
+++ b/src/java/org/apache/poi/hssf/util/CellReference.java
@@ -36,17 +36,17 @@ public final class CellReference {
public static final int NAMED_RANGE = 2;
public static final int BAD_CELL_OR_NAMED_RANGE = -1;
}
- /** The character ($) that signifies a row or column value is absolute instead of relative */
- private static final char ABSOLUTE_REFERENCE_MARKER = '$';
- /** The character (!) that separates sheet names from cell references */
- private static final char SHEET_NAME_DELIMITER = '!';
- /** The character (') used to quote sheet names when they contain special characters */
- private static final char SPECIAL_NAME_DELIMITER = '\'';
-
- /**
- * Matches a run of letters followed by a run of digits. The run of letters is group 1 and the
- * run of digits is group 2. Each group may optionally be prefixed with a single '$'.
- */
+ /** The character ($) that signifies a row or column value is absolute instead of relative */
+ private static final char ABSOLUTE_REFERENCE_MARKER = '$';
+ /** The character (!) that separates sheet names from cell references */
+ private static final char SHEET_NAME_DELIMITER = '!';
+ /** The character (') used to quote sheet names when they contain special characters */
+ private static final char SPECIAL_NAME_DELIMITER = '\'';
+
+ /**
+ * Matches a run of letters followed by a run of digits. The run of letters is group 1 and the
+ * run of digits is group 2. Each group may optionally be prefixed with a single '$'.
+ */
private static final Pattern CELL_REF_PATTERN = Pattern.compile("\\$?([A-Za-z]+)\\$?([0-9]+)");
/**
* Named range names must start with a letter or underscore. Subsequent characters may include
@@ -58,89 +58,103 @@ public final class CellReference {
private static final String BIFF8_LAST_ROW = String.valueOf(0x10000);
private static final int BIFF8_LAST_ROW_TEXT_LEN = BIFF8_LAST_ROW.length();
- private final int _rowIndex;
- private final int _colIndex;
- private final String _sheetName;
- private final boolean _isRowAbs;
- private final boolean _isColAbs;
+ private final int _rowIndex;
+ private final int _colIndex;
+ private final String _sheetName;
+ private final boolean _isRowAbs;
+ private final boolean _isColAbs;
- /**
- * Create an cell ref from a string representation. Sheet names containing special characters should be
- * delimited and escaped as per normal syntax rules for formulas.
- */
- public CellReference(String cellRef) {
- String[] parts = separateRefParts(cellRef);
- _sheetName = parts[0];
- String colRef = parts[1];
- if (colRef.length() < 1) {
- throw new IllegalArgumentException("Invalid Formula cell reference: '"+cellRef+"'");
- }
- _isColAbs = colRef.charAt(0) == '$';
- if (_isColAbs) {
- colRef=colRef.substring(1);
- }
- _colIndex = convertColStringToNum(colRef);
-
- String rowRef=parts[2];
- if (rowRef.length() < 1) {
- throw new IllegalArgumentException("Invalid Formula cell reference: '"+cellRef+"'");
- }
- _isRowAbs = rowRef.charAt(0) == '$';
- if (_isRowAbs) {
- rowRef=rowRef.substring(1);
- }
- _rowIndex = Integer.parseInt(rowRef)-1; // -1 to convert 1-based to zero-based
- }
-
- public CellReference(int pRow, int pCol) {
- this(pRow, pCol, false, false);
- }
- public CellReference(int pRow, short pCol) {
- this(pRow, (int)pCol, false, false);
- }
-
- public CellReference(int pRow, int pCol, boolean pAbsRow, boolean pAbsCol) {
- this(null, pRow, pCol, pAbsRow, pAbsCol);
- }
- public CellReference(String pSheetName, int pRow, int pCol, boolean pAbsRow, boolean pAbsCol) {
- // TODO - "-1" is a special value being temporarily used for whole row and whole column area references.
- // so these checks are currently N.Q.R.
- if(pRow < -1) {
- throw new IllegalArgumentException("row index may not be negative");
- }
- if(pCol < -1) {
- throw new IllegalArgumentException("column index may not be negative");
- }
- _sheetName = pSheetName;
- _rowIndex=pRow;
- _colIndex=pCol;
- _isRowAbs = pAbsRow;
- _isColAbs=pAbsCol;
- }
-
- public int getRow(){return _rowIndex;}
- public short getCol(){return (short) _colIndex;}
- public boolean isRowAbsolute(){return _isRowAbs;}
- public boolean isColAbsolute(){return _isColAbs;}
- /**
- * @return possibly null
if this is a 2D reference. Special characters are not
- * escaped or delimited
- */
- public String getSheetName(){
- return _sheetName;
- }
-
- /**
- * takes in a column reference portion of a CellRef and converts it from
- * ALPHA-26 number format to 0-based base 10.
- */
- private int convertColStringToNum(String ref) {
- int lastIx = ref.length()-1;
- int retval=0;
- int pos = 0;
+ /**
+ * Create an cell ref from a string representation. Sheet names containing special characters should be
+ * delimited and escaped as per normal syntax rules for formulas.
+ */
+ public CellReference(String cellRef) {
+ String[] parts = separateRefParts(cellRef);
+ _sheetName = parts[0];
+ String colRef = parts[1];
+ if (colRef.length() < 1) {
+ throw new IllegalArgumentException("Invalid Formula cell reference: '"+cellRef+"'");
+ }
+ _isColAbs = colRef.charAt(0) == '$';
+ if (_isColAbs) {
+ colRef=colRef.substring(1);
+ }
+ _colIndex = convertColStringToIndex(colRef);
- for (int k = lastIx; k > -1; k--) {
+ String rowRef=parts[2];
+ if (rowRef.length() < 1) {
+ throw new IllegalArgumentException("Invalid Formula cell reference: '"+cellRef+"'");
+ }
+ _isRowAbs = rowRef.charAt(0) == '$';
+ if (_isRowAbs) {
+ rowRef=rowRef.substring(1);
+ }
+ _rowIndex = Integer.parseInt(rowRef)-1; // -1 to convert 1-based to zero-based
+ }
+
+ public CellReference(int pRow, int pCol) {
+ this(pRow, pCol, false, false);
+ }
+ public CellReference(int pRow, short pCol) {
+ this(pRow, pCol & 0xFFFF, false, false);
+ }
+
+ public CellReference(int pRow, int pCol, boolean pAbsRow, boolean pAbsCol) {
+ this(null, pRow, pCol, pAbsRow, pAbsCol);
+ }
+ public CellReference(String pSheetName, int pRow, int pCol, boolean pAbsRow, boolean pAbsCol) {
+ // TODO - "-1" is a special value being temporarily used for whole row and whole column area references.
+ // so these checks are currently N.Q.R.
+ if(pRow < -1) {
+ throw new IllegalArgumentException("row index may not be negative");
+ }
+ if(pCol < -1) {
+ throw new IllegalArgumentException("column index may not be negative");
+ }
+ _sheetName = pSheetName;
+ _rowIndex=pRow;
+ _colIndex=pCol;
+ _isRowAbs = pAbsRow;
+ _isColAbs=pAbsCol;
+ }
+
+ public int getRow(){return _rowIndex;}
+ public short getCol(){return (short) _colIndex;}
+ public boolean isRowAbsolute(){return _isRowAbs;}
+ public boolean isColAbsolute(){return _isColAbs;}
+ /**
+ * @return possibly null
if this is a 2D reference. Special characters are not
+ * escaped or delimited
+ */
+ public String getSheetName(){
+ return _sheetName;
+ }
+
+ public static boolean isPartAbsolute(String part) {
+ return part.charAt(0) == ABSOLUTE_REFERENCE_MARKER;
+ }
+ /**
+ * takes in a column reference portion of a CellRef and converts it from
+ * ALPHA-26 number format to 0-based base 10.
+ * 'A' -> 0
+ * 'Z' -> 25
+ * 'AA' -> 26
+ * 'IV' -> 255
+ * @return zero based column index
+ */
+ public static int convertColStringToIndex(String ref) {
+
+ int pos = 0;
+ int retval=0;
+ for (int k = ref.length()-1; k >= 0; k--) {
char thechar = ref.charAt(k);
+ if (thechar == ABSOLUTE_REFERENCE_MARKER) {
+ if (k != 0) {
+ throw new IllegalArgumentException("Bad col ref format '"
+ + ref + "'");
+ }
+ break;
+ }
// Character.getNumericValue() returns the values
// 10-35 for the letter A-Z
int shift = (int)Math.pow(26, pos);
@@ -148,64 +162,64 @@ public final class CellReference {
pos++;
}
return retval-1;
- }
+ }
- /**
- * Classifies an identifier as either a simple (2D) cell reference or a named range name
- * @return one of the values from NameType
- */
- public static int classifyCellReference(String str) {
- int len = str.length();
- if (len < 1) {
- throw new IllegalArgumentException("Empty string not allowed");
- }
- char firstChar = str.charAt(0);
- switch (firstChar) {
- case ABSOLUTE_REFERENCE_MARKER:
- case '.':
- case '_':
- break;
- default:
- if (!Character.isLetter(firstChar)) {
- throw new IllegalArgumentException("Invalid first char (" + firstChar
- + ") of cell reference or named range. Letter expected");
- }
- }
- if (!Character.isDigit(str.charAt(len-1))) {
- // no digits at end of str
- return validateNamedRangeName(str);
- }
- Matcher cellRefPatternMatcher = CELL_REF_PATTERN.matcher(str);
- if (!cellRefPatternMatcher.matches()) {
- return validateNamedRangeName(str);
- }
- String lettersGroup = cellRefPatternMatcher.group(1);
- String digitsGroup = cellRefPatternMatcher.group(2);
- if (cellReferenceIsWithinRange(lettersGroup, digitsGroup)) {
- // valid cell reference
- return NameType.CELL;
- }
- // If str looks like a cell reference, but is out of (row/col) range, it is a valid
- // named range name
- // This behaviour is a little weird. For example, "IW123" is a valid named range name
- // because the column "IW" is beyond the maximum "IV". Note - this behaviour is version
- // dependent. In Excel 2007, "IW123" is not a valid named range name.
- if (str.indexOf(ABSOLUTE_REFERENCE_MARKER) >= 0) {
- // Of course, named range names cannot have '$'
- return NameType.BAD_CELL_OR_NAMED_RANGE;
- }
- return NameType.NAMED_RANGE;
- }
+ /**
+ * Classifies an identifier as either a simple (2D) cell reference or a named range name
+ * @return one of the values from NameType
+ */
+ public static int classifyCellReference(String str) {
+ int len = str.length();
+ if (len < 1) {
+ throw new IllegalArgumentException("Empty string not allowed");
+ }
+ char firstChar = str.charAt(0);
+ switch (firstChar) {
+ case ABSOLUTE_REFERENCE_MARKER:
+ case '.':
+ case '_':
+ break;
+ default:
+ if (!Character.isLetter(firstChar)) {
+ throw new IllegalArgumentException("Invalid first char (" + firstChar
+ + ") of cell reference or named range. Letter expected");
+ }
+ }
+ if (!Character.isDigit(str.charAt(len-1))) {
+ // no digits at end of str
+ return validateNamedRangeName(str);
+ }
+ Matcher cellRefPatternMatcher = CELL_REF_PATTERN.matcher(str);
+ if (!cellRefPatternMatcher.matches()) {
+ return validateNamedRangeName(str);
+ }
+ String lettersGroup = cellRefPatternMatcher.group(1);
+ String digitsGroup = cellRefPatternMatcher.group(2);
+ if (cellReferenceIsWithinRange(lettersGroup, digitsGroup)) {
+ // valid cell reference
+ return NameType.CELL;
+ }
+ // If str looks like a cell reference, but is out of (row/col) range, it is a valid
+ // named range name
+ // This behaviour is a little weird. For example, "IW123" is a valid named range name
+ // because the column "IW" is beyond the maximum "IV". Note - this behaviour is version
+ // dependent. In Excel 2007, "IW123" is not a valid named range name.
+ if (str.indexOf(ABSOLUTE_REFERENCE_MARKER) >= 0) {
+ // Of course, named range names cannot have '$'
+ return NameType.BAD_CELL_OR_NAMED_RANGE;
+ }
+ return NameType.NAMED_RANGE;
+ }
- private static int validateNamedRangeName(String str) {
+ private static int validateNamedRangeName(String str) {
if (!NAMED_RANGE_NAME_PATTERN.matcher(str).matches()) {
return NameType.BAD_CELL_OR_NAMED_RANGE;
}
return NameType.NAMED_RANGE;
}
-
-
+
+
/**
* Used to decide whether a name of the form "[A-Z]*[0-9]*" that appears in a formula can be
* interpreted as a cell reference. Names of that form can be also used for sheets and/or
@@ -226,7 +240,7 @@ public final class CellReference {
*
* Input |
- * Result |
+ * Result |
* "A", "1" | true |
* "a", "111" | true |
* "A", "65536" | true |
@@ -275,86 +289,86 @@ public final class CellReference {
}
/**
- * Separates the row from the columns and returns an array of three Strings. The first element
- * is the sheet name. Only the first element may be null. The second element in is the column
- * name still in ALPHA-26 number format. The third element is the row.
- */
- private static String[] separateRefParts(String reference) {
-
- int plingPos = reference.lastIndexOf(SHEET_NAME_DELIMITER);
- String sheetName = parseSheetName(reference, plingPos);
- int start = plingPos+1;
+ * Separates the row from the columns and returns an array of three Strings. The first element
+ * is the sheet name. Only the first element may be null. The second element in is the column
+ * name still in ALPHA-26 number format. The third element is the row.
+ */
+ private static String[] separateRefParts(String reference) {
+
+ int plingPos = reference.lastIndexOf(SHEET_NAME_DELIMITER);
+ String sheetName = parseSheetName(reference, plingPos);
+ int start = plingPos+1;
- int length = reference.length();
+ int length = reference.length();
- int loc = start;
- // skip initial dollars
- if (reference.charAt(loc)==ABSOLUTE_REFERENCE_MARKER) {
- loc++;
- }
- // step over column name chars until first digit (or dollars) for row number.
- for (; loc < length; loc++) {
- char ch = reference.charAt(loc);
- if (Character.isDigit(ch) || ch == ABSOLUTE_REFERENCE_MARKER) {
- break;
- }
- }
- return new String[] {
- sheetName,
- reference.substring(start,loc),
- reference.substring(loc),
- };
- }
+ int loc = start;
+ // skip initial dollars
+ if (reference.charAt(loc)==ABSOLUTE_REFERENCE_MARKER) {
+ loc++;
+ }
+ // step over column name chars until first digit (or dollars) for row number.
+ for (; loc < length; loc++) {
+ char ch = reference.charAt(loc);
+ if (Character.isDigit(ch) || ch == ABSOLUTE_REFERENCE_MARKER) {
+ break;
+ }
+ }
+ return new String[] {
+ sheetName,
+ reference.substring(start,loc),
+ reference.substring(loc),
+ };
+ }
- private static String parseSheetName(String reference, int indexOfSheetNameDelimiter) {
- if(indexOfSheetNameDelimiter < 0) {
- return null;
- }
-
- boolean isQuoted = reference.charAt(0) == SPECIAL_NAME_DELIMITER;
- if(!isQuoted) {
- return reference.substring(0, indexOfSheetNameDelimiter);
- }
- int lastQuotePos = indexOfSheetNameDelimiter-1;
- if(reference.charAt(lastQuotePos) != SPECIAL_NAME_DELIMITER) {
- throw new RuntimeException("Mismatched quotes: (" + reference + ")");
- }
+ private static String parseSheetName(String reference, int indexOfSheetNameDelimiter) {
+ if(indexOfSheetNameDelimiter < 0) {
+ return null;
+ }
+
+ boolean isQuoted = reference.charAt(0) == SPECIAL_NAME_DELIMITER;
+ if(!isQuoted) {
+ return reference.substring(0, indexOfSheetNameDelimiter);
+ }
+ int lastQuotePos = indexOfSheetNameDelimiter-1;
+ if(reference.charAt(lastQuotePos) != SPECIAL_NAME_DELIMITER) {
+ throw new RuntimeException("Mismatched quotes: (" + reference + ")");
+ }
- // TODO - refactor cell reference parsing logic to one place.
- // Current known incarnations:
- // FormulaParser.GetName()
- // CellReference.parseSheetName() (here)
- // AreaReference.separateAreaRefs()
- // SheetNameFormatter.format() (inverse)
-
- StringBuffer sb = new StringBuffer(indexOfSheetNameDelimiter);
-
- for(int i=1; i D
- */
- protected static String convertNumToColString(int col) {
+ /**
+ * Takes in a 0-based base-10 column and returns a ALPHA-26
+ * representation.
+ * eg column #3 -> D
+ */
+ protected static String convertNumToColString(int col) {
// Excel counts column A as the 1st column, we
// treat it as the 0th one
int excelColNum = col + 1;
@@ -373,35 +387,35 @@ public final class CellReference {
}
return colRef;
- }
+ }
- /**
- * Example return values:
- *
- * Result | Comment |
- * A1 | Cell reference without sheet |
- * Sheet1!A1 | Standard sheet name |
- * 'O''Brien''s Sales'!A1' | Sheet name with special characters |
- *
- * @return the text representation of this cell reference as it would appear in a formula.
- */
- public String formatAsString() {
- StringBuffer sb = new StringBuffer(32);
- if(_sheetName != null) {
- SheetNameFormatter.appendFormat(sb, _sheetName);
- sb.append(SHEET_NAME_DELIMITER);
- }
- appendCellReference(sb);
- return sb.toString();
- }
-
- public String toString() {
- StringBuffer sb = new StringBuffer(64);
- sb.append(getClass().getName()).append(" [");
- sb.append(formatAsString());
- sb.append("]");
- return sb.toString();
- }
+ /**
+ * Example return values:
+ *
+ * Result | Comment |
+ * A1 | Cell reference without sheet |
+ * Sheet1!A1 | Standard sheet name |
+ * 'O''Brien''s Sales'!A1' | Sheet name with special characters |
+ *
+ * @return the text representation of this cell reference as it would appear in a formula.
+ */
+ public String formatAsString() {
+ StringBuffer sb = new StringBuffer(32);
+ if(_sheetName != null) {
+ SheetNameFormatter.appendFormat(sb, _sheetName);
+ sb.append(SHEET_NAME_DELIMITER);
+ }
+ appendCellReference(sb);
+ return sb.toString();
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer(64);
+ sb.append(getClass().getName()).append(" [");
+ sb.append(formatAsString());
+ sb.append("]");
+ return sb.toString();
+ }
/**
* Returns the three parts of the cell reference, the
@@ -419,18 +433,18 @@ public final class CellReference {
};
}
- /**
- * Appends cell reference with '$' markers for absolute values as required.
- * Sheet name is not included.
- */
- /* package */ void appendCellReference(StringBuffer sb) {
- if(_isColAbs) {
- sb.append(ABSOLUTE_REFERENCE_MARKER);
- }
- sb.append( convertNumToColString(_colIndex));
- if(_isRowAbs) {
- sb.append(ABSOLUTE_REFERENCE_MARKER);
- }
- sb.append(_rowIndex+1);
- }
+ /**
+ * Appends cell reference with '$' markers for absolute values as required.
+ * Sheet name is not included.
+ */
+ /* package */ void appendCellReference(StringBuffer sb) {
+ if(_isColAbs) {
+ sb.append(ABSOLUTE_REFERENCE_MARKER);
+ }
+ sb.append( convertNumToColString(_colIndex));
+ if(_isRowAbs) {
+ sb.append(ABSOLUTE_REFERENCE_MARKER);
+ }
+ sb.append(_rowIndex+1);
+ }
}
diff --git a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java
index d1f70a0ad..d4f100cfc 100644
--- a/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java
+++ b/src/testcases/org/apache/poi/hssf/usermodel/TestHSSFFormulaEvaluator.java
@@ -40,4 +40,43 @@ public final class TestHSSFFormulaEvaluator extends TestCase {
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, cv.getCellType());
assertEquals(3.72, cv.getNumberValue(), 0.0);
}
+
+ public void testFullColumnRefs() {
+ HSSFWorkbook wb = new HSSFWorkbook();
+ HSSFSheet sheet = wb.createSheet("Sheet1");
+ HSSFRow row = sheet.createRow(0);
+ HSSFCell cell0 = row.createCell(0);
+ cell0.setCellFormula("sum(D:D)");
+ HSSFCell cell1 = row.createCell(1);
+ cell1.setCellFormula("sum(D:E)");
+
+ // some values in column D
+ setValue(sheet, 1, 3, 5.0);
+ setValue(sheet, 2, 3, 6.0);
+ setValue(sheet, 5, 3, 7.0);
+ setValue(sheet, 50, 3, 8.0);
+
+ // some values in column E
+ setValue(sheet, 1, 4, 9.0);
+ setValue(sheet, 2, 4, 10.0);
+ setValue(sheet, 30000, 4, 11.0);
+
+ // some other values
+ setValue(sheet, 1, 2, 100.0);
+ setValue(sheet, 2, 5, 100.0);
+ setValue(sheet, 3, 6, 100.0);
+
+
+ HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(sheet, wb);
+ assertEquals(26.0, fe.evaluate(cell0).getNumberValue(), 0.0);
+ assertEquals(56.0, fe.evaluate(cell1).getNumberValue(), 0.0);
+ }
+
+ private static void setValue(HSSFSheet sheet, int rowIndex, int colIndex, double value) {
+ HSSFRow row = sheet.getRow(rowIndex);
+ if (row == null) {
+ row = sheet.createRow(rowIndex);
+ }
+ row.createCell(colIndex).setCellValue(value);
+ }
}
diff --git a/src/testcases/org/apache/poi/hssf/util/TestAreaReference.java b/src/testcases/org/apache/poi/hssf/util/TestAreaReference.java
index c8424287c..0b6d73462 100644
--- a/src/testcases/org/apache/poi/hssf/util/TestAreaReference.java
+++ b/src/testcases/org/apache/poi/hssf/util/TestAreaReference.java
@@ -83,7 +83,7 @@ public final class TestAreaReference extends TestCase {
public void testReferenceWithSheet() {
AreaReference ar;
- ar = new AreaReference("Tabelle1!B5");
+ ar = new AreaReference("Tabelle1!B5:B5");
assertTrue(ar.isSingleCell());
TestCellReference.confirmCell(ar.getFirstCell(), "Tabelle1", 4, 1, false, false, "Tabelle1!B5");
@@ -113,11 +113,11 @@ public final class TestAreaReference extends TestCase {
}
}
- public void testContiguousReferences() throws Exception {
- String refSimple = "$C$10";
+ public void testContiguousReferences() {
+ String refSimple = "$C$10:$C$10";
String ref2D = "$C$10:$D$11";
- String refDCSimple = "$C$10,$D$12,$E$14";
- String refDC2D = "$C$10:$C$11,$D$12,$E$14:$E$20";
+ String refDCSimple = "$C$10:$C$10,$D$12:$D$12,$E$14:$E$14";
+ String refDC2D = "$C$10:$C$11,$D$12:$D$12,$E$14:$E$20";
String refDC3D = "Tabelle1!$C$10:$C$14,Tabelle1!$D$10:$D$12";
// Check that we detect as contiguous properly
@@ -243,16 +243,16 @@ public final class TestAreaReference extends TestCase {
private static void confirmResolveCellRef(HSSFWorkbook wb, CellReference cref) {
HSSFSheet s = wb.getSheet(cref.getSheetName());
HSSFRow r = s.getRow(cref.getRow());
- HSSFCell c = r.getCell(cref.getCol());
+ HSSFCell c = r.getCell((int)cref.getCol());
assertNotNull(c);
}
public void testSpecialSheetNames() {
AreaReference ar;
- ar = new AreaReference("'Sheet A'!A1");
+ ar = new AreaReference("'Sheet A'!A1:A1");
confirmAreaSheetName(ar, "Sheet A", "'Sheet A'!A1");
- ar = new AreaReference("'Hey! Look Here!'!A1");
+ ar = new AreaReference("'Hey! Look Here!'!A1:A1");
confirmAreaSheetName(ar, "Hey! Look Here!", "'Hey! Look Here!'!A1");
ar = new AreaReference("'O''Toole'!A1:B2");
@@ -268,7 +268,24 @@ public final class TestAreaReference extends TestCase {
assertEquals(expectedFullText, ar.formatAsString());
}
- public static void main(String[] args) {
- junit.textui.TestRunner.run(TestAreaReference.class);
- }
+ public void testWholeColumnRefs() {
+ confirmWholeColumnRef("A:A", 0, 0, false, false);
+ confirmWholeColumnRef("$C:D", 2, 3, true, false);
+ confirmWholeColumnRef("AD:$AE", 29, 30, false, true);
+
+ }
+
+ private static void confirmWholeColumnRef(String ref, int firstCol, int lastCol, boolean firstIsAbs, boolean lastIsAbs) {
+ AreaReference ar = new AreaReference(ref);
+ confirmCell(ar.getFirstCell(), 0, firstCol, true, firstIsAbs);
+ confirmCell(ar.getLastCell(), 0xFFFF, lastCol, true, lastIsAbs);
+ }
+
+ private static void confirmCell(CellReference cell, int row, int col, boolean isRowAbs,
+ boolean isColAbs) {
+ assertEquals(row, cell.getRow());
+ assertEquals(col, cell.getCol());
+ assertEquals(isRowAbs, cell.isRowAbsolute());
+ assertEquals(isColAbs, cell.isColAbsolute());
+ }
}