/**
* Matches a run of one or more letters followed by a run of one or more digits.
+ * Both the letter and number groups are optional.
* 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]+)");
+ private static final Pattern CELL_REF_PATTERN = Pattern.compile("(\\$?[A-Z]+)?" + "(\\$?[0-9]+)?", Pattern.CASE_INSENSITIVE);
+ /**
+ * Matches references only where row and column are included.
+ * Matches a run of one or more letters followed by a run of one or more digits.
+ * If a reference does not match this pattern, it might match COLUMN_REF_PATTERN or ROW_REF_PATTERN
+ * References may optionally include a single '$' before each group, but these are excluded from the Matcher.group(int).
+ */
+ private static final Pattern STRICTLY_CELL_REF_PATTERN = Pattern.compile("\\$?([A-Z]+)" + "\\$?([0-9]+)", Pattern.CASE_INSENSITIVE);
/**
* Matches a run of one or more letters. The run of letters is group 1.
- * The text may optionally be prefixed with a single '$'.
+ * References may optionally include a single '$' before the group, but these are excluded from the Matcher.group(int).
*/
- private static final Pattern COLUMN_REF_PATTERN = Pattern.compile("\\$?([A-Za-z]+)");
+ private static final Pattern COLUMN_REF_PATTERN = Pattern.compile("\\$?([A-Z]+)", Pattern.CASE_INSENSITIVE);
/**
- * Matches a run of one or more digits. The run of digits is group 1.
- * The text may optionally be prefixed with a single '$'.
+ * Matches a run of one or more letters. The run of numbers is group 1.
+ * References may optionally include a single '$' before the group, but these are excluded from the Matcher.group(int).
*/
private static final Pattern ROW_REF_PATTERN = Pattern.compile("\\$?([0-9]+)");
/**
* Named range names must start with a letter or underscore. Subsequent characters may include
* digits or dot. (They can even end in dot).
*/
- private static final Pattern NAMED_RANGE_NAME_PATTERN = Pattern.compile("[_A-Za-z][_.A-Za-z0-9]*");
+ private static final Pattern NAMED_RANGE_NAME_PATTERN = Pattern.compile("[_A-Z][_.A-Z0-9]*", Pattern.CASE_INSENSITIVE);
//private static final String BIFF8_LAST_COLUMN = SpreadsheetVersion.EXCEL97.getLastColumnName();
//private static final int BIFF8_LAST_COLUMN_TEXT_LEN = BIFF8_LAST_COLUMN.length();
//private static final String BIFF8_LAST_ROW = String.valueOf(SpreadsheetVersion.EXCEL97.getMaxRows());
// no digits at end of str
return validateNamedRangeName(str, ssVersion);
}
- Matcher cellRefPatternMatcher = CELL_REF_PATTERN.matcher(str);
+ Matcher cellRefPatternMatcher = STRICTLY_CELL_REF_PATTERN.matcher(str);
if (!cellRefPatternMatcher.matches()) {
return validateNamedRangeName(str, ssVersion);
}
Matcher colMatcher = COLUMN_REF_PATTERN.matcher(str);
if (colMatcher.matches()) {
String colStr = colMatcher.group(1);
- if (isColumnWithnRange(colStr, ssVersion)) {
+ if (isColumnWithinRange(colStr, ssVersion)) {
return NameType.COLUMN;
}
}
Matcher rowMatcher = ROW_REF_PATTERN.matcher(str);
if (rowMatcher.matches()) {
String rowStr = rowMatcher.group(1);
- if (isRowWithnRange(rowStr, ssVersion)) {
+ if (isRowWithinRange(rowStr, ssVersion)) {
return NameType.ROW;
}
}
* @return <code>true</code> if the row and col parameters are within range of a BIFF8 spreadsheet.
*/
public static boolean cellReferenceIsWithinRange(String colStr, String rowStr, SpreadsheetVersion ssVersion) {
- if (!isColumnWithnRange(colStr, ssVersion)) {
+ if (!isColumnWithinRange(colStr, ssVersion)) {
return false;
}
- return isRowWithnRange(rowStr, ssVersion);
+ return isRowWithinRange(rowStr, ssVersion);
}
+ /**
+ * @deprecated 3.15 beta 2. Use {@link #isColumnWithinRange}.
+ */
public static boolean isColumnWithnRange(String colStr, SpreadsheetVersion ssVersion) {
+ return isColumnWithinRange(colStr, ssVersion);
+ }
+
+ public static boolean isColumnWithinRange(String colStr, SpreadsheetVersion ssVersion) {
+ // Equivalent to 0 <= CellReference.convertColStringToIndex(colStr) <= ssVersion.getLastColumnIndex()
+
String lastCol = ssVersion.getLastColumnName();
int lastColLength = lastCol.length();
return true;
}
+ /**
+ * @deprecated 3.15 beta 2. Use {@link #isRowWithinRange}
+ */
public static boolean isRowWithnRange(String rowStr, SpreadsheetVersion ssVersion) {
+ return isRowWithinRange(rowStr, ssVersion);
+ }
+
+ public static boolean isRowWithinRange(String rowStr, SpreadsheetVersion ssVersion) {
int rowNum = Integer.parseInt(rowStr);
if (rowNum < 0) {
private CellRefParts(String sheetName, String rowRef, String colRef) {
this.sheetName = sheetName;
- this.rowRef = rowRef;
- this.colRef = colRef;
+ this.rowRef = (rowRef != null) ? rowRef : "";
+ this.colRef = (colRef != null) ? colRef : "";
}
}
private static CellRefParts separateRefParts(String reference) {
int plingPos = reference.lastIndexOf(SHEET_NAME_DELIMITER);
final String sheetName = parseSheetName(reference, plingPos);
- String row;
- String col;
- int start = plingPos+1;
-
- 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;
- }
- }
+ String cell = reference.substring(plingPos+1).toUpperCase(Locale.ROOT);
+ Matcher matcher = CELL_REF_PATTERN.matcher(cell);
+ if (!matcher.matches()) throw new IllegalArgumentException("Invalid CellReference: " + reference);
+ String col = matcher.group(1);
+ String row = matcher.group(2);
- col = reference.substring(start,loc).toUpperCase(Locale.ROOT);
- row = reference.substring(loc);
CellRefParts cellRefParts = new CellRefParts(sheetName, row, col);
return cellRefParts;
}