Merged revisions 707953,708242,708252,708260,708262,708286 via svnmerge from
https://svn.apache.org/repos/asf/poi/trunk ........ r707953 | josh | 2008-10-26 01:17:06 -0700 (Sun, 26 Oct 2008) | 1 line Bugzilla 45966 - added implementation for FIND function (patch from Torstein Tauno Svendsen). ........ r708242 | nick | 2008-10-27 10:26:52 -0700 (Mon, 27 Oct 2008) | 1 line Link typo fix ........ r708252 | nick | 2008-10-27 10:59:39 -0700 (Mon, 27 Oct 2008) | 1 line Patch from bug #46092 - fix hssf dev utility ........ r708260 | josh | 2008-10-27 11:12:09 -0700 (Mon, 27 Oct 2008) | 1 line Removed obsolete class ........ r708262 | josh | 2008-10-27 11:16:44 -0700 (Mon, 27 Oct 2008) | 1 line Bugzilla 46065 - added implementation for VALUE function ........ r708286 | josh | 2008-10-27 12:24:42 -0700 (Mon, 27 Oct 2008) | 1 line Preparation for fix for bug 46009. (Bug visible on ooxml branch, but this change will expose the problem) ........ git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@708325 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
6175b9b1fb
commit
8a6625a237
@ -37,6 +37,8 @@
|
||||
|
||||
<!-- Don't forget to update status.xml too! -->
|
||||
<release version="3.5-beta4" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="add">46065 - added implementation for VALUE function</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">45966 - added implementation for FIND function</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45778 - fixed ObjRecord to read ftLbsData properly</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">46053 - fixed evaluation cache dependency analysis when changing blank cells</action>
|
||||
</release>
|
||||
|
@ -99,7 +99,7 @@
|
||||
org.apache.poi.hssf.record.formula.FormulaParser</strong> class. This class implements a hand
|
||||
written recursive descent parser.
|
||||
</p>
|
||||
<p>Check out the <link href="http://poi.apache.org/javadocs/">javadocs </link> for details.
|
||||
<p>Check out the <link href="http://poi.apache.org/apidocs/">javadocs </link> for details.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
|
@ -34,6 +34,8 @@
|
||||
<!-- Don't forget to update changes.xml too! -->
|
||||
<changes>
|
||||
<release version="3.5-beta4" date="2008-??-??">
|
||||
<action dev="POI-DEVELOPERS" type="add">46065 - added implementation for VALUE function</action>
|
||||
<action dev="POI-DEVELOPERS" type="add">45966 - added implementation for FIND function</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">45778 - fixed ObjRecord to read ftLbsData properly</action>
|
||||
<action dev="POI-DEVELOPERS" type="fix">46053 - fixed evaluation cache dependency analysis when changing blank cells</action>
|
||||
</release>
|
||||
|
@ -15,7 +15,6 @@
|
||||
limitations under the License.
|
||||
==================================================================== */
|
||||
|
||||
|
||||
package org.apache.poi.hssf.dev;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
@ -30,7 +29,7 @@ import org.apache.poi.hssf.usermodel.HSSFRichTextString;
|
||||
import org.apache.poi.hssf.usermodel.HSSFRow;
|
||||
import org.apache.poi.hssf.usermodel.HSSFSheet;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.hssf.util.CellRangeAddress;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||
import org.apache.poi.ss.util.Region;
|
||||
|
||||
@ -222,7 +221,7 @@ public class HSSF
|
||||
if (args.length < 2)
|
||||
{
|
||||
|
||||
/* try
|
||||
try
|
||||
{
|
||||
HSSF hssf = new HSSF(args[ 0 ]);
|
||||
|
||||
@ -231,26 +230,30 @@ public class HSSF
|
||||
|
||||
for (int k = 0; k < wb.getNumberOfSheets(); k++)
|
||||
{
|
||||
System.out.println("Sheet " + k);
|
||||
HSSFSheet sheet = wb.getSheetAt(k);
|
||||
int rows = sheet.getPhysicalNumberOfRows();
|
||||
|
||||
System.out.println("Sheet " + k + " \""
|
||||
+ wb.getSheetName(k) + "\" has "
|
||||
+ rows + " row(s).");
|
||||
for (int r = 0; r < rows; r++)
|
||||
{
|
||||
HSSFRow row = sheet.getPhysicalRowAt(r);
|
||||
int cells = row.getPhysicalNumberOfCells();
|
||||
|
||||
System.out.println("ROW " + row.getRowNum());
|
||||
HSSFRow row = sheet.getRow(r);
|
||||
int cells = (row != null) ? row.getPhysicalNumberOfCells() : 0;
|
||||
if (row != null) {
|
||||
System.out.println("\nROW " + row.getRowNum()
|
||||
+ " has " + cells + " cell(s).");
|
||||
}
|
||||
for (int c = 0; c < cells; c++)
|
||||
{
|
||||
HSSFCell cell = row.getPhysicalCellAt(c);
|
||||
HSSFCell cell = row.getCell(c);
|
||||
String value = null;
|
||||
|
||||
switch (cell.getCellType())
|
||||
{
|
||||
|
||||
case HSSFCell.CELL_TYPE_FORMULA :
|
||||
value = "FORMULA ";
|
||||
value = "FORMULA value="
|
||||
+ cell.getCellFormula();
|
||||
break;
|
||||
|
||||
case HSSFCell.CELL_TYPE_NUMERIC :
|
||||
@ -275,7 +278,7 @@ public class HSSF
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}*/
|
||||
}
|
||||
}
|
||||
else if (args.length == 2)
|
||||
{
|
||||
|
@ -68,7 +68,7 @@ import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
|
||||
import org.apache.poi.hssf.record.aggregates.RecordAggregate.PositionTrackingVisitor;
|
||||
import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
|
||||
import org.apache.poi.hssf.record.formula.FormulaShifter;
|
||||
import org.apache.poi.hssf.util.CellRangeAddress;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.hssf.util.PaneInformation;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
@ -51,8 +51,8 @@ public final class CFHeaderRecord extends Record {
|
||||
{
|
||||
field_1_numcf = in.readShort();
|
||||
field_2_need_recalculation = in.readShort();
|
||||
field_3_enclosing_cell_range = new org.apache.poi.hssf.util.CellRangeAddress(in);
|
||||
field_4_cell_ranges = new org.apache.poi.hssf.util.CellRangeAddressList(in);
|
||||
field_3_enclosing_cell_range = new CellRangeAddress(in);
|
||||
field_4_cell_ranges = new CellRangeAddressList(in);
|
||||
}
|
||||
|
||||
public int getNumberOfConditionalFormats()
|
||||
|
@ -50,7 +50,7 @@ public final class MergeCellsRecord extends Record {
|
||||
int nRegions = in.readUShort();
|
||||
CellRangeAddress[] cras = new CellRangeAddress[nRegions];
|
||||
for (int i = 0; i < nRegions; i++) {
|
||||
cras[i] = new org.apache.poi.hssf.util.CellRangeAddress(in);
|
||||
cras[i] = new CellRangeAddress(in);
|
||||
}
|
||||
_numberOfRegions = nRegions;
|
||||
_startIndex = 0;
|
||||
|
@ -22,8 +22,8 @@ import java.util.List;
|
||||
|
||||
import org.apache.poi.hssf.model.RecordStream;
|
||||
import org.apache.poi.hssf.record.MergeCellsRecord;
|
||||
import org.apache.poi.hssf.util.CellRangeAddress;
|
||||
import org.apache.poi.hssf.util.CellRangeAddressList;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
import org.apache.poi.ss.util.CellRangeAddressList;
|
||||
|
||||
/**
|
||||
*
|
||||
@ -51,7 +51,8 @@ public final class MergedCellsTable extends RecordAggregate {
|
||||
MergeCellsRecord mcr = (MergeCellsRecord) rs.getNext();
|
||||
int nRegions = mcr.getNumAreas();
|
||||
for (int i = 0; i < nRegions; i++) {
|
||||
temp.add(mcr.getAreaAt(i));
|
||||
CellRangeAddress cra = mcr.getAreaAt(i);
|
||||
temp.add(cra);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -102,7 +103,8 @@ public final class MergedCellsTable extends RecordAggregate {
|
||||
private void addMergeCellsRecord(MergeCellsRecord mcr) {
|
||||
int nRegions = mcr.getNumAreas();
|
||||
for (int i = 0; i < nRegions; i++) {
|
||||
_mergedRegions.add(mcr.getAreaAt(i));
|
||||
CellRangeAddress cra = mcr.getAreaAt(i);
|
||||
_mergedRegions.add(cra);
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,5 +132,4 @@ public final class MergedCellsTable extends RecordAggregate {
|
||||
public int getNumberOfMergedRegions() {
|
||||
return _mergedRegions.size();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,96 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
* Created on May 14, 2005
|
||||
*
|
||||
*/
|
||||
package org.apache.poi.hssf.record.formula.eval;
|
||||
|
||||
/**
|
||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
||||
*
|
||||
*/
|
||||
public abstract class StringOperationEval implements OperationEval {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns an instanceof StringValueEval or ErrorEval or BlankEval
|
||||
*
|
||||
* @param eval
|
||||
* @param srcRow
|
||||
* @param srcCol
|
||||
*/
|
||||
protected ValueEval singleOperandEvaluate(Eval eval, int srcRow, short srcCol) {
|
||||
ValueEval retval;
|
||||
if (eval instanceof AreaEval) {
|
||||
AreaEval ae = (AreaEval) eval;
|
||||
if (ae.contains(srcRow, srcCol)) { // circular ref!
|
||||
retval = ErrorEval.CIRCULAR_REF_ERROR;
|
||||
}
|
||||
else if (ae.isRow()) {
|
||||
if (ae.containsColumn(srcCol)) {
|
||||
ValueEval ve = ae.getValueAt(ae.getFirstRow(), srcCol);
|
||||
retval = internalResolveEval(eval);
|
||||
}
|
||||
else {
|
||||
retval = ErrorEval.NAME_INVALID;
|
||||
}
|
||||
}
|
||||
else if (ae.isColumn()) {
|
||||
if (ae.containsRow(srcRow)) {
|
||||
ValueEval ve = ae.getValueAt(srcRow, ae.getFirstColumn());
|
||||
retval = internalResolveEval(eval);
|
||||
}
|
||||
else {
|
||||
retval = ErrorEval.NAME_INVALID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
retval = ErrorEval.NAME_INVALID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
retval = internalResolveEval(eval);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
private ValueEval internalResolveEval(Eval eval) {
|
||||
ValueEval retval;
|
||||
if (eval instanceof StringValueEval) {
|
||||
retval = (StringValueEval) eval;
|
||||
}
|
||||
else if (eval instanceof RefEval) {
|
||||
RefEval re = (RefEval) eval;
|
||||
ValueEval tve = re.getInnerValueEval();
|
||||
if (tve instanceof StringValueEval || tve instanceof BlankEval) {
|
||||
retval = tve;
|
||||
}
|
||||
else {
|
||||
retval = ErrorEval.NAME_INVALID;
|
||||
}
|
||||
}
|
||||
else if (eval instanceof BlankEval) {
|
||||
retval = (BlankEval) eval;
|
||||
}
|
||||
else {
|
||||
retval = ErrorEval.NAME_INVALID;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
}
|
@ -1,25 +1,65 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
* Created on May 15, 2005
|
||||
*
|
||||
*/
|
||||
/* ====================================================================
|
||||
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;
|
||||
|
||||
public class Find extends NotImplementedFunction {
|
||||
import org.apache.poi.hssf.record.formula.eval.Eval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.EvaluationException;
|
||||
|
||||
/**
|
||||
* Implementation of the FIND() function.<p/>
|
||||
*
|
||||
* <b>Syntax</b>:<br/>
|
||||
* <b>FIND</b>(<b>find_text</b>, <b>within_text</b>, start_num)<p/>
|
||||
*
|
||||
* FIND returns the character position of the first occurrence of <tt>find_text</tt> inside
|
||||
* <tt>within_text</tt>. The third parameter, <tt>start_num</tt>, is optional (default=1)
|
||||
* and specifies where to start searching from. Character positions are 1-based.<p/>
|
||||
*
|
||||
* @author Torstein Tauno Svendsen (torstei@officenet.no)
|
||||
*/
|
||||
public class Find extends TextFunction {
|
||||
|
||||
protected ValueEval evaluateFunc(Eval[] args, int srcCellRow, short srcCellCol)
|
||||
throws EvaluationException {
|
||||
|
||||
int nArgs = args.length;
|
||||
if (nArgs < 2 || nArgs > 3) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
String needle = evaluateStringArg(args[0], srcCellRow, srcCellCol);
|
||||
String haystack = evaluateStringArg(args[1], srcCellRow, srcCellCol);
|
||||
int startpos;
|
||||
if (nArgs == 3) {
|
||||
startpos = evaluateIntArg(args[2], srcCellRow, srcCellCol);
|
||||
if (startpos <= 0) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
startpos--; // convert 1-based to zero based
|
||||
} else {
|
||||
startpos = 0;
|
||||
}
|
||||
int result = haystack.indexOf(needle, startpos);
|
||||
if (result == -1) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
return new NumberEval(result + 1);
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,188 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
* Created on May 15, 2005
|
||||
*
|
||||
*/
|
||||
/* ====================================================================
|
||||
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;
|
||||
|
||||
public class Value extends NotImplementedFunction {
|
||||
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.Eval;
|
||||
import org.apache.poi.hssf.record.formula.eval.EvaluationException;
|
||||
import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.OperandResolver;
|
||||
import org.apache.poi.hssf.record.formula.eval.ValueEval;
|
||||
|
||||
/**
|
||||
* Implementation for Excel VALUE() function.<p/>
|
||||
*
|
||||
* <b>Syntax</b>:<br/> <b>VALUE</b>(<b>text</b>)<br/>
|
||||
*
|
||||
* Converts the text argument to a number. Leading and/or trailing whitespace is
|
||||
* ignored. Currency symbols and thousands separators are stripped out.
|
||||
* Scientific notation is also supported. If the supplied text does not convert
|
||||
* properly the result is <b>#VALUE!</b> error. Blank string converts to zero.
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public final class Value implements Function {
|
||||
|
||||
/** "1,0000" is valid, "1,00" is not */
|
||||
private static final int MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR = 4;
|
||||
private static final Double ZERO = new Double(0.0);
|
||||
|
||||
public Eval evaluate(Eval[] args, int srcCellRow, short srcCellCol) {
|
||||
if (args.length != 1) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
ValueEval veText;
|
||||
try {
|
||||
veText = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
|
||||
} catch (EvaluationException e) {
|
||||
return e.getErrorEval();
|
||||
}
|
||||
String strText = OperandResolver.coerceValueToString(veText);
|
||||
Double result = convertTextToNumber(strText);
|
||||
if (result == null) {
|
||||
return ErrorEval.VALUE_INVALID;
|
||||
}
|
||||
return new NumberEval(result.doubleValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO see if the same functionality is needed in {@link OperandResolver#parseDouble(String)}
|
||||
*
|
||||
* @return <code>null</code> if there is any problem converting the text
|
||||
*/
|
||||
private static Double convertTextToNumber(String strText) {
|
||||
boolean foundCurrency = false;
|
||||
boolean foundUnaryPlus = false;
|
||||
boolean foundUnaryMinus = false;
|
||||
|
||||
int len = strText.length();
|
||||
int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
char ch = strText.charAt(i);
|
||||
if (Character.isDigit(ch) || ch == '.') {
|
||||
break;
|
||||
}
|
||||
switch (ch) {
|
||||
case ' ':
|
||||
// intervening spaces between '$', '-', '+' are OK
|
||||
continue;
|
||||
case '$':
|
||||
if (foundCurrency) {
|
||||
// only one currency symbols is allowed
|
||||
return null;
|
||||
}
|
||||
foundCurrency = true;
|
||||
continue;
|
||||
case '+':
|
||||
if (foundUnaryMinus || foundUnaryPlus) {
|
||||
return null;
|
||||
}
|
||||
foundUnaryPlus = true;
|
||||
continue;
|
||||
case '-':
|
||||
if (foundUnaryMinus || foundUnaryPlus) {
|
||||
return null;
|
||||
}
|
||||
foundUnaryMinus = true;
|
||||
continue;
|
||||
default:
|
||||
// all other characters are illegal
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (i >= len) {
|
||||
// didn't find digits or '.'
|
||||
if (foundCurrency || foundUnaryMinus || foundUnaryPlus) {
|
||||
return null;
|
||||
}
|
||||
return ZERO;
|
||||
}
|
||||
|
||||
// remove thousands separators
|
||||
|
||||
boolean foundDecimalPoint = false;
|
||||
int lastThousandsSeparatorIndex = Short.MIN_VALUE;
|
||||
|
||||
StringBuffer sb = new StringBuffer(len);
|
||||
for (; i < len; i++) {
|
||||
char ch = strText.charAt(i);
|
||||
if (Character.isDigit(ch)) {
|
||||
sb.append(ch);
|
||||
continue;
|
||||
}
|
||||
switch (ch) {
|
||||
case ' ':
|
||||
String remainingText = strText.substring(i);
|
||||
if (remainingText.trim().length() > 0) {
|
||||
// intervening spaces not allowed once the digits start
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
case '.':
|
||||
if (foundDecimalPoint) {
|
||||
return null;
|
||||
}
|
||||
if (i - lastThousandsSeparatorIndex < MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR) {
|
||||
return null;
|
||||
}
|
||||
foundDecimalPoint = true;
|
||||
sb.append('.');
|
||||
continue;
|
||||
case ',':
|
||||
if (foundDecimalPoint) {
|
||||
// thousands separators not allowed after '.' or 'E'
|
||||
return null;
|
||||
}
|
||||
int distanceBetweenThousandsSeparators = i - lastThousandsSeparatorIndex;
|
||||
// as long as there are 3 or more digits between
|
||||
if (distanceBetweenThousandsSeparators < MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR) {
|
||||
return null;
|
||||
}
|
||||
lastThousandsSeparatorIndex = i;
|
||||
// don't append ','
|
||||
continue;
|
||||
|
||||
case 'E':
|
||||
case 'e':
|
||||
if (i - lastThousandsSeparatorIndex < MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR) {
|
||||
return null;
|
||||
}
|
||||
// append rest of strText and skip to end of loop
|
||||
sb.append(strText.substring(i));
|
||||
i = len;
|
||||
break;
|
||||
default:
|
||||
// all other characters are illegal
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (!foundDecimalPoint) {
|
||||
if (i - lastThousandsSeparatorIndex < MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
double d;
|
||||
try {
|
||||
d = Double.parseDouble(sb.toString());
|
||||
} catch (NumberFormatException e) {
|
||||
// still a problem parsing the number - probably out of range
|
||||
return null;
|
||||
}
|
||||
return new Double(foundUnaryMinus ? -d : d);
|
||||
}
|
||||
}
|
||||
|
@ -670,7 +670,7 @@ public class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet
|
||||
/**
|
||||
* @return the merged region at the specified index
|
||||
*/
|
||||
public org.apache.poi.hssf.util.CellRangeAddress getMergedRegion(int index) {
|
||||
public CellRangeAddress getMergedRegion(int index) {
|
||||
return sheet.getMergedRegionAt(index);
|
||||
}
|
||||
|
||||
|
@ -18,12 +18,12 @@ package org.apache.poi.hssf.util;
|
||||
|
||||
import org.apache.poi.hssf.record.RecordInputStream;
|
||||
import org.apache.poi.hssf.record.SelectionRecord;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
* See OOO documentation: excelfileformat.pdf sec 2.5.14 - 'Cell Range Address'<p/>
|
||||
*
|
||||
* Note - {@link SelectionRecord} uses the BIFF5 version of this structure
|
||||
* @deprecated use {@link org.apache.poi.ss.util.CellRangeAddress}
|
||||
* @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
|
||||
*/
|
||||
public class CellRangeAddress extends org.apache.poi.ss.util.CellRangeAddress {
|
||||
|
@ -33,6 +33,8 @@ import org.apache.poi.util.LittleEndian;
|
||||
* range address (called an ADDR structure) contains 4 16-bit-values.
|
||||
* </p>
|
||||
*
|
||||
* @deprecated use {@link org.apache.poi.ss.util.CellRangeAddressList}
|
||||
*
|
||||
* @author Dragos Buleandra (dragos.buleandra@trade2b.ro)
|
||||
*/
|
||||
public class CellRangeAddressList extends org.apache.poi.ss.util.CellRangeAddressList {
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package org.apache.poi.ss.util;
|
||||
|
||||
import org.apache.poi.hssf.record.RecordInputStream;
|
||||
import org.apache.poi.hssf.record.SelectionRecord;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
@ -42,6 +43,17 @@ public class CellRangeAddress extends CellRangeAddressBase {
|
||||
LittleEndian.putUShort(data, offset + 6, getLastColumn());
|
||||
return ENCODED_SIZE;
|
||||
}
|
||||
public CellRangeAddress(RecordInputStream in) {
|
||||
super(readUShortAndCheck(in), in.readUShort(), in.readUShort(), in.readUShort());
|
||||
}
|
||||
|
||||
private static int readUShortAndCheck(RecordInputStream in) {
|
||||
if (in.remaining() < ENCODED_SIZE) {
|
||||
// Ran out of data
|
||||
throw new RuntimeException("Ran out of data reading CellRangeAddress");
|
||||
}
|
||||
return in.readUShort();
|
||||
}
|
||||
|
||||
public CellRangeAddress copy() {
|
||||
return new CellRangeAddress(getFirstRow(), getLastRow(), getFirstColumn(), getLastColumn());
|
||||
|
@ -18,6 +18,8 @@ package org.apache.poi.ss.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.hssf.record.RecordInputStream;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
|
||||
/**
|
||||
@ -51,7 +53,17 @@ public class CellRangeAddressList {
|
||||
this();
|
||||
addCellRangeAddress(firstRow, firstCol, lastRow, lastCol);
|
||||
}
|
||||
/**
|
||||
* @param in the RecordInputstream to read the record from
|
||||
*/
|
||||
public CellRangeAddressList(RecordInputStream in) {
|
||||
this();
|
||||
int nItems = in.readUShort();
|
||||
|
||||
for (int k = 0; k < nItems; k++) {
|
||||
_list.add(new CellRangeAddress(in));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get the number of following ADDR structures. The number of this
|
||||
* structures is automatically set when reading an Excel file and/or
|
||||
|
@ -17,10 +17,18 @@
|
||||
|
||||
package org.apache.poi.hssf.record;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.model.RecordStream;
|
||||
import org.apache.poi.hssf.record.aggregates.MergedCellsTable;
|
||||
import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
|
||||
|
||||
/**
|
||||
* Make sure the merge cells record behaves
|
||||
* @author Danny Mui (dmui at apache dot org)
|
||||
@ -28,25 +36,45 @@ import org.apache.poi.ss.util.CellRangeAddress;
|
||||
*/
|
||||
public final class TestMergeCellsRecord extends TestCase {
|
||||
|
||||
/**
|
||||
* Make sure when a clone is called, we actually clone it.
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testCloneReferences() throws Exception {
|
||||
CellRangeAddress[] cras = { new CellRangeAddress(0, 1, 0, 2), };
|
||||
MergeCellsRecord merge = new MergeCellsRecord(cras, 0, cras.length);
|
||||
MergeCellsRecord clone = (MergeCellsRecord)merge.clone();
|
||||
/**
|
||||
* Make sure when a clone is called, we actually clone it.
|
||||
*/
|
||||
public void testCloneReferences() {
|
||||
CellRangeAddress[] cras = { new CellRangeAddress(0, 1, 0, 2), };
|
||||
MergeCellsRecord merge = new MergeCellsRecord(cras, 0, cras.length);
|
||||
MergeCellsRecord clone = (MergeCellsRecord)merge.clone();
|
||||
|
||||
assertNotSame("Merged and cloned objects are the same", merge, clone);
|
||||
|
||||
CellRangeAddress mergeRegion = merge.getAreaAt(0);
|
||||
CellRangeAddress cloneRegion = clone.getAreaAt(0);
|
||||
assertNotSame("Should not point to same objects when cloning", mergeRegion, cloneRegion);
|
||||
assertEquals("New Clone Row From doesnt match", mergeRegion.getFirstRow(), cloneRegion.getFirstRow());
|
||||
assertEquals("New Clone Row To doesnt match", mergeRegion.getLastRow(), cloneRegion.getLastRow());
|
||||
assertEquals("New Clone Col From doesnt match", mergeRegion.getFirstColumn(), cloneRegion.getFirstColumn());
|
||||
assertEquals("New Clone Col To doesnt match", mergeRegion.getLastColumn(), cloneRegion.getLastColumn());
|
||||
|
||||
assertNotSame("Merged and cloned objects are the same", merge, clone);
|
||||
|
||||
CellRangeAddress mergeRegion = merge.getAreaAt(0);
|
||||
CellRangeAddress cloneRegion = clone.getAreaAt(0);
|
||||
assertNotSame("Should not point to same objects when cloning", mergeRegion, cloneRegion);
|
||||
assertEquals("New Clone Row From doesnt match", mergeRegion.getFirstRow(), cloneRegion.getFirstRow());
|
||||
assertEquals("New Clone Row To doesnt match", mergeRegion.getLastRow(), cloneRegion.getLastRow());
|
||||
assertEquals("New Clone Col From doesnt match", mergeRegion.getFirstColumn(), cloneRegion.getFirstColumn());
|
||||
assertEquals("New Clone Col To doesnt match", mergeRegion.getLastColumn(), cloneRegion.getLastColumn());
|
||||
|
||||
assertFalse(merge.getAreaAt(0) == clone.getAreaAt(0));
|
||||
}
|
||||
assertFalse(merge.getAreaAt(0) == clone.getAreaAt(0));
|
||||
}
|
||||
|
||||
private static final RecordVisitor dummyRecordVisitor = new RecordVisitor() {
|
||||
public void visitRecord(Record r) {
|
||||
// do nothing
|
||||
}
|
||||
};
|
||||
public void testMCTable_bug46009() {
|
||||
MergedCellsTable mct = new MergedCellsTable();
|
||||
List recList = new ArrayList();
|
||||
CellRangeAddress[] cras = new CellRangeAddress[] {
|
||||
new CellRangeAddress(0, 0, 0, 3),
|
||||
};
|
||||
recList.add(new MergeCellsRecord(cras, 0, 1));
|
||||
RecordStream rs = new RecordStream(recList, 0);
|
||||
mct.read(rs);
|
||||
try {
|
||||
mct.visitContainedRecords(dummyRecordVisitor);
|
||||
} catch (ArrayStoreException e) {
|
||||
throw new AssertionFailedError("Identified bug 46009");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ public final class AllIndividualFunctionEvaluationTests {
|
||||
result.addTestSuite(TestAverage.class);
|
||||
result.addTestSuite(TestCountFuncs.class);
|
||||
result.addTestSuite(TestDate.class);
|
||||
result.addTestSuite(TestFind.class);
|
||||
result.addTestSuite(TestFinanceLib.class);
|
||||
result.addTestSuite(TestIndex.class);
|
||||
result.addTestSuite(TestIndexFunctionFromSpreadsheet.class);
|
||||
@ -49,6 +50,7 @@ public final class AllIndividualFunctionEvaluationTests {
|
||||
result.addTestSuite(TestStatsLib.class);
|
||||
result.addTestSuite(TestTFunc.class);
|
||||
result.addTestSuite(TestTrim.class);
|
||||
result.addTestSuite(TestValue.class);
|
||||
result.addTestSuite(TestXYNumericFunction.class);
|
||||
return result;
|
||||
}
|
||||
|
@ -0,0 +1,76 @@
|
||||
/* ====================================================================
|
||||
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 junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.usermodel.HSSFCell;
|
||||
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
|
||||
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
|
||||
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
||||
import org.apache.poi.ss.usermodel.CellValue;
|
||||
|
||||
/**
|
||||
* Tests for {@link Find}
|
||||
*
|
||||
* @author Torstein Svendsen (torstei@officenet.no)
|
||||
*/
|
||||
public final class TestFind extends TestCase {
|
||||
|
||||
public void testFind() {
|
||||
HSSFWorkbook wb = new HSSFWorkbook();
|
||||
HSSFCell cell = wb.createSheet().createRow(0).createCell(0);
|
||||
|
||||
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
|
||||
|
||||
confirmResult(fe, cell, "find(\"h\", \"haystack\")", 1);
|
||||
confirmResult(fe, cell, "find(\"a\", \"haystack\",2)", 2);
|
||||
confirmResult(fe, cell, "find(\"a\", \"haystack\",3)", 6);
|
||||
|
||||
// number args converted to text
|
||||
confirmResult(fe, cell, "find(7, 32768)", 3);
|
||||
confirmResult(fe, cell, "find(\"34\", 1341235233412, 3)", 10);
|
||||
confirmResult(fe, cell, "find(5, 87654)", 4);
|
||||
|
||||
// Errors
|
||||
confirmError(fe, cell, "find(\"n\", \"haystack\")", HSSFErrorConstants.ERROR_VALUE);
|
||||
confirmError(fe, cell, "find(\"k\", \"haystack\",9)", HSSFErrorConstants.ERROR_VALUE);
|
||||
confirmError(fe, cell, "find(\"k\", \"haystack\",#REF!)", HSSFErrorConstants.ERROR_REF);
|
||||
confirmError(fe, cell, "find(\"k\", \"haystack\",0)", HSSFErrorConstants.ERROR_VALUE);
|
||||
confirmError(fe, cell, "find(#DIV/0!, #N/A, #REF!)", HSSFErrorConstants.ERROR_DIV_0);
|
||||
confirmError(fe, cell, "find(2, #N/A, #REF!)", HSSFErrorConstants.ERROR_NA);
|
||||
}
|
||||
|
||||
private static void confirmResult(HSSFFormulaEvaluator fe, HSSFCell cell, String formulaText,
|
||||
int expectedResult) {
|
||||
cell.setCellFormula(formulaText);
|
||||
fe.notifyUpdateCell(cell);
|
||||
CellValue result = fe.evaluate(cell);
|
||||
assertEquals(result.getCellType(), HSSFCell.CELL_TYPE_NUMERIC);
|
||||
assertEquals(expectedResult, result.getNumberValue(), 0.0);
|
||||
}
|
||||
|
||||
private static void confirmError(HSSFFormulaEvaluator fe, HSSFCell cell, String formulaText,
|
||||
int expectedErrorCode) {
|
||||
cell.setCellFormula(formulaText);
|
||||
fe.notifyUpdateCell(cell);
|
||||
CellValue result = fe.evaluate(cell);
|
||||
assertEquals(result.getCellType(), HSSFCell.CELL_TYPE_ERROR);
|
||||
assertEquals(expectedErrorCode, result.getErrorValue());
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/* ====================================================================
|
||||
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 junit.framework.TestCase;
|
||||
|
||||
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.Eval;
|
||||
import org.apache.poi.hssf.record.formula.eval.NumberEval;
|
||||
import org.apache.poi.hssf.record.formula.eval.StringEval;
|
||||
|
||||
/**
|
||||
* Tests for {@link Value}
|
||||
*
|
||||
* @author Josh Micich
|
||||
*/
|
||||
public final class TestValue extends TestCase {
|
||||
|
||||
private static Eval invokeValue(String strText) {
|
||||
Eval[] args = new Eval[] { new StringEval(strText), };
|
||||
return new Value().evaluate(args, -1, (short) -1);
|
||||
}
|
||||
|
||||
private static void confirmValue(String strText, double expected) {
|
||||
Eval result = invokeValue(strText);
|
||||
assertEquals(NumberEval.class, result.getClass());
|
||||
assertEquals(expected, ((NumberEval) result).getNumberValue(), 0.0);
|
||||
}
|
||||
|
||||
private static void confirmValueError(String strText) {
|
||||
Eval result = invokeValue(strText);
|
||||
assertEquals(ErrorEval.class, result.getClass());
|
||||
assertEquals(ErrorEval.VALUE_INVALID, result);
|
||||
}
|
||||
|
||||
public void testBasic() {
|
||||
|
||||
confirmValue("100", 100);
|
||||
confirmValue("-2.3", -2.3);
|
||||
confirmValue(".5", 0.5);
|
||||
confirmValue(".5e2", 50);
|
||||
confirmValue(".5e-2", 0.005);
|
||||
confirmValue(".5e+2", 50);
|
||||
confirmValue("+5", 5);
|
||||
confirmValue("$1,000", 1000);
|
||||
confirmValue("100.5e1", 1005);
|
||||
confirmValue("1,0000", 10000);
|
||||
confirmValue("1,000,0000", 10000000);
|
||||
confirmValue("1,000,0000,00000", 1000000000000.0);
|
||||
confirmValue(" 100 ", 100);
|
||||
confirmValue(" + 100", 100);
|
||||
confirmValue("10000", 10000);
|
||||
confirmValue("$-5", -5);
|
||||
confirmValue("$.5", 0.5);
|
||||
confirmValue("123e+5", 12300000);
|
||||
confirmValue("1,000e2", 100000);
|
||||
confirmValue("$10e2", 1000);
|
||||
confirmValue("$1,000e2", 100000);
|
||||
}
|
||||
|
||||
public void testErrors() {
|
||||
confirmValueError("1+1");
|
||||
confirmValueError("1 1");
|
||||
confirmValueError("1,00.0");
|
||||
confirmValueError("1,00");
|
||||
confirmValueError("$1,00.5e1");
|
||||
confirmValueError("1,00.5e1");
|
||||
confirmValueError("1,0,000");
|
||||
confirmValueError("1,00,000");
|
||||
confirmValueError("++100");
|
||||
confirmValueError("$$5");
|
||||
confirmValueError("-");
|
||||
confirmValueError("+");
|
||||
confirmValueError("$");
|
||||
confirmValueError(",300");
|
||||
confirmValueError("0.233,4");
|
||||
confirmValueError("1e2.5");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user