Improved Formula Parser support for ranges and exponents, from Pavel Krupets (Bug #43410)

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@576855 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2007-09-18 11:53:28 +00:00
parent 1f056652b7
commit 031873f7e6
4 changed files with 149 additions and 54 deletions

View File

@ -36,6 +36,8 @@
</devs>
<release version="3.0.2-FINAL" date="2007-??-??">
<action dev="POI-DEVELOPERS" type="fix">43410 - [PATCH] - Improved Formula Parser support for numbers and ranges</action>
<action dev="POI-DEVELOPERS" type="add">When writing HSLF files out, optionally preserve all OLE2 nodes (default is just the HSLF related nodes)</action>
<action dev="POI-DEVELOPERS" type="add">43323 - [PATCH] - Support for adding Pictures to ShapeGroups in HSLF.</action>
<action dev="POI-DEVELOPERS" type="add">43222 - [PATCH] - Support for getting OLE object data from HSSFWorkbook.</action>
<action dev="POI-DEVELOPERS" type="add">43247 - [PATCH] - Support for getting OLE object data from slideshows.</action>

View File

@ -33,6 +33,8 @@
<changes>
<release version="3.0.2-FINAL" date="2007-??-??">
<action dev="POI-DEVELOPERS" type="fix">43410 - [PATCH] - Improved Formula Parser support for numbers and ranges</action>
<action dev="POI-DEVELOPERS" type="add">When writing HSLF files out, optionally preserve all OLE2 nodes (default is just the HSLF related nodes)</action>
<action dev="POI-DEVELOPERS" type="add">43323 - [PATCH] - Support for adding Pictures to ShapeGroups in HSLF.</action>
<action dev="POI-DEVELOPERS" type="add">43222 - [PATCH] - Support for getting OLE object data from HSSFWorkbook.</action>
<action dev="POI-DEVELOPERS" type="add">43247 - [PATCH] - Support for getting OLE object data from slideshows.</action>

View File

@ -45,6 +45,7 @@ import org.apache.poi.hssf.record.formula.*;
* @author Eric Ladner (eladner at goldinc dot com)
* @author Cameron Riley (criley at ekmail.com)
* @author Peter M. Murray (pete at quantrix dot com)
* @author Pavel Krupets (pkrupets at palmtreebusiness dot com)
*/
public class FormulaParser {
@ -230,36 +231,21 @@ public class FormulaParser {
}
/** Get the exponent for numbers of form 1.3E21 */
private String GetExponent() {
StringBuffer retval = new StringBuffer();
String sign = "";
GetChar();
if ('-' == look) {
sign = "-";
GetChar();
}
while (IsDigit(look)) {
retval.append(look);
GetChar();
}
if (retval.length() > 0) {
retval.insert(0, sign);
}
return retval.toString();
}
/** Get a Number */
private String GetNum() {
StringBuffer value = new StringBuffer();
if (!IsDigit(look)) Expected("Integer");
while (IsDigit(look)){
value.append(look);
while (IsDigit(this.look)){
value.append(this.look);
GetChar();
}
SkipWhite();
return value.toString();
return value.length() == 0 ? null : value.toString();
}
/** Output a String with Tab */
private void Emit(String s){
System.out.print(TAB+s);
@ -278,9 +264,14 @@ public class FormulaParser {
if (look == '('){
//This is a function
function(name);
} else if (look == ':') { // this is a AreaReference
} else if (look == ':' || look == '.') { // this is a AreaReference
GetChar();
while (look == '.') { // formulas can have . or .. or ... instead of :
GetChar();
}
String first = name;
Match(':');
String second = GetName();
tokens.add(new AreaPtg(first+":"+second));
} else if (look == '!') {
@ -508,43 +499,81 @@ public class FormulaParser {
} else if (look == ')' || look == ',') {
tokens.add(new MissingArgPtg());
} else {
String number = GetNum();
if (look=='.') {
Match('.');
String decimalPart = null;
if (IsDigit(look)) number = number +"."+ GetNum(); //this also takes care of someone entering "1234."
if ('E' == look) {
String exponent = GetExponent();
number += 'E' + exponent;
String number2 = null;
String exponent = null;
String number1 = GetNum();
if (look == '.') {
GetChar();
number2 = GetNum();
}
if (look == 'E') {
GetChar();
String sign = "";
if (look == '+') {
GetChar();
} else if (look == '-') {
GetChar();
sign = "-";
}
tokens.add(new NumberPtg(number));
String number = GetNum();
if (number == null) {
Expected("Integer");
}
exponent = sign + number;
}
else if ('E' == look) {
String exponent = GetExponent();
number += 'E'+exponent;
tokens.add(new NumberPtg(number));
}
else {
tokens.add(getNumberPtgFromString(number)); //TODO:what if the number is too big to be a short? ..add factory to return Int or Number!
if (number1 == null && number2 == null) {
Expected("Integer");
}
tokens.add(getNumberPtgFromString(number1, number2, exponent));
}
}
/** Get a PTG for an integer from its string representation.
* return Int or Number Ptg based on size of input
* @param number
/**
* Get a PTG for an integer from its string representation.
* return Int or Number Ptg based on size of input
*/
private Ptg getNumberPtgFromString(String number) {
try {
return new IntPtg(number);
} catch (NumberFormatException e) {
return new NumberPtg(number);
}
private Ptg getNumberPtgFromString(String number1, String number2, String exponent) {
StringBuffer number = new StringBuffer();
if (number2 == null) {
number.append(number1);
if (exponent != null) {
number.append('E');
number.append(exponent);
}
String numberStr = number.toString();
try {
return new IntPtg(numberStr);
} catch (NumberFormatException e) {
return new NumberPtg(numberStr);
}
} else {
if (number1 != null) {
number.append(number1);
}
number.append('.');
number.append(number2);
if (exponent != null) {
number.append('E');
number.append(exponent);
}
return new NumberPtg(number.toString());
}
}
private void StringLiteral()
{
// Can't use match here 'cuz it consumes whitespace

View File

@ -507,4 +507,66 @@ public class TestFormulaParser extends TestCase {
System.out.println("Testing org.apache.poi.hssf.record.formula.FormulaParser");
junit.textui.TestRunner.run(TestFormulaParser.class);
}
public void testNumbers() {
HSSFWorkbook wb = new HSSFWorkbook();
wb.createSheet("Cash_Flow");;
HSSFSheet sheet = wb.createSheet("Test");
HSSFRow row = sheet.createRow(0);
HSSFCell cell = row.createCell((short)0);
String formula = null;
// starts from decimal point
cell.setCellFormula(".1");
formula = cell.getCellFormula();
assertEquals("0.1", formula);
cell.setCellFormula("+.1");
formula = cell.getCellFormula();
assertEquals("+0.1", formula);
cell.setCellFormula("-.1");
formula = cell.getCellFormula();
assertEquals("-0.1", formula);
// has exponent
cell.setCellFormula("10E1");
formula = cell.getCellFormula();
assertEquals("100.0", formula);
cell.setCellFormula("10E+1");
formula = cell.getCellFormula();
assertEquals("100.0", formula);
cell.setCellFormula("10E-1");
formula = cell.getCellFormula();
assertEquals("1.0", formula);
}
public void testRanges() {
HSSFWorkbook wb = new HSSFWorkbook();
wb.createSheet("Cash_Flow");;
HSSFSheet sheet = wb.createSheet("Test");
HSSFRow row = sheet.createRow(0);
HSSFCell cell = row.createCell((short)0);
String formula = null;
cell.setCellFormula("A1.A2");
formula = cell.getCellFormula();
assertEquals("A1:A2", formula);
cell.setCellFormula("A1..A2");
formula = cell.getCellFormula();
assertEquals("A1:A2", formula);
cell.setCellFormula("A1...A2");
formula = cell.getCellFormula();
assertEquals("A1:A2", formula);
}
}