Support for Mid, Replace and Substitute excel functions (bug #s 44095, 44097, 44099)

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@606172 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2007-12-21 12:24:54 +00:00
parent 952c2e002d
commit 76b94fc202
6 changed files with 258 additions and 3 deletions

View File

@ -36,6 +36,7 @@
<!-- Don't forget to update status.xml too! -->
<release version="3.0.2-FINAL" date="2007-??-??">
<action dev="POI-DEVELOPERS" type="add">44095, 44097, 44099 - [PATCH] Support for Mid, Replace and Substitute excel functions</action>
<action dev="POI-DEVELOPERS" type="add">44055 - [PATCH] Support for getting the from field from HSMF messages</action>
<action dev="POI-DEVELOPERS" type="add">43551 - [PATCH] Support for 1904 date windowing in HSSF (previously only supported 1900 date windowing)</action>
<action dev="POI-DEVELOPERS" type="add">41064 - [PATCH] Support for String continue records</action>

View File

@ -33,6 +33,7 @@
<!-- Don't forget to update changes.xml too! -->
<changes>
<release version="3.0.2-FINAL" date="2007-??-??">
<action dev="POI-DEVELOPERS" type="add">44095, 44097, 44099 - [PATCH] Support for Mid, Replace and Substitute excel functions</action>
<action dev="POI-DEVELOPERS" type="add">44055 - [PATCH] Support for getting the from field from HSMF messages</action>
<action dev="POI-DEVELOPERS" type="add">43551 - [PATCH] Support for 1904 date windowing in HSSF (previously only supported 1900 date windowing)</action>
<action dev="POI-DEVELOPERS" type="add">41064 - [PATCH] Support for String continue records</action>

View File

@ -20,6 +20,80 @@
*/
package org.apache.poi.hssf.record.formula.functions;
public class Mid extends NotImplementedFunction {
import org.apache.poi.hssf.record.formula.eval.BlankEval;
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.NumericValueEval;
import org.apache.poi.hssf.record.formula.eval.StringEval;
import org.apache.poi.hssf.record.formula.eval.StringValueEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
/**
* An implementation of the MID function:
* Returns a specific number of characters from a text string,
* starting at the position you specify, based on the number
* of characters you specify.
* @author Manda Wilson &lt; wilson at c bio dot msk cc dot org &gt;
*/
public class Mid extends TextFunction {
/**
* Returns a specific number of characters from a text string,
* starting at the position you specify, based on the number
* of characters you specify.
*
* @see org.apache.poi.hssf.record.formula.eval.Eval
*/
public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
Eval retval = null;
String str = null;
int startNum = 0;
int numChars = 0;
switch (operands.length) {
default:
retval = ErrorEval.VALUE_INVALID;
case 3:
// first operand is text string containing characters to extract
// second operand is position of first character to extract
// third operand is the number of characters to return
ValueEval firstveval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
ValueEval secondveval = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol);
ValueEval thirdveval = singleOperandEvaluate(operands[2], srcCellRow, srcCellCol);
if (firstveval instanceof StringValueEval
&& secondveval instanceof NumericValueEval
&& thirdveval instanceof NumericValueEval) {
StringValueEval strEval = (StringValueEval) firstveval;
str = strEval.getStringValue();
NumericValueEval startNumEval = (NumericValueEval) secondveval;
// NOTE: it is safe to cast to int here
// because in Excel =MID("test", 1, 1.7) returns t
// so 1.7 must be truncated to 1
// and =MID("test", 1.9, 2) returns te
// so 1.9 must be truncated to 1
startNum = (int) startNumEval.getNumberValue();
NumericValueEval numCharsEval = (NumericValueEval) thirdveval;
numChars = (int) numCharsEval.getNumberValue();
} else {
retval = ErrorEval.VALUE_INVALID;
}
}
if (retval == null) {
if (startNum < 1 || numChars < 0) {
retval = ErrorEval.VALUE_INVALID;
} else if (startNum > str.length() || numChars == 0) {
retval = BlankEval.INSTANCE;
} else if (startNum + numChars > str.length()) {
retval = new StringEval(str.substring(startNum - 1));
} else {
retval = new StringEval(str.substring(startNum - 1, numChars));
}
}
return retval;
}
}

View File

@ -20,6 +20,93 @@
*/
package org.apache.poi.hssf.record.formula.functions;
public class Replace 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.NumericValueEval;
import org.apache.poi.hssf.record.formula.eval.StringEval;
import org.apache.poi.hssf.record.formula.eval.StringValueEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
/**
* An implementation of the REPLACE function:
* Replaces part of a text string based on the number of characters
* you specify, with another text string.
* @author Manda Wilson &lt; wilson at c bio dot msk cc dot org &gt;
*/
public class Replace extends TextFunction {
/**
* Replaces part of a text string based on the number of characters
* you specify, with another text string.
*
* @see org.apache.poi.hssf.record.formula.eval.Eval
*/
public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
Eval retval = null;
String oldStr = null;
String newStr = null;
int startNum = 0;
int numChars = 0;
switch (operands.length) {
default:
retval = ErrorEval.VALUE_INVALID;
case 4:
// first operand is text string containing characters to replace
// second operand is position of first character to replace
// third operand is the number of characters in the old string
// you want to replace with new string
// fourth operand is the new string
ValueEval firstveval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
ValueEval secondveval = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol);
ValueEval thirdveval = singleOperandEvaluate(operands[2], srcCellRow, srcCellCol);
ValueEval fourthveval = singleOperandEvaluate(operands[3], srcCellRow, srcCellCol);
if (firstveval instanceof StringValueEval
&& secondveval instanceof NumericValueEval
&& thirdveval instanceof NumericValueEval
&& fourthveval instanceof StringValueEval) {
StringValueEval oldStrEval = (StringValueEval) firstveval;
oldStr = oldStrEval.getStringValue();
NumericValueEval startNumEval = (NumericValueEval) secondveval;
// NOTE: it is safe to cast to int here
// because in Excel =REPLACE("task", 2.7, 3, "est")
// returns test
// so 2.7 must be truncated to 2
// and =REPLACE("task", 1, 1.9, "") returns ask
// so 1.9 must be truncated to 1
startNum = (int) startNumEval.getNumberValue();
NumericValueEval numCharsEval = (NumericValueEval) thirdveval;
numChars = (int) numCharsEval.getNumberValue();
StringValueEval newStrEval = (StringValueEval) fourthveval;
newStr = newStrEval.getStringValue();
} else {
retval = ErrorEval.VALUE_INVALID;
}
}
if (retval == null) {
if (startNum < 1 || numChars < 0) {
retval = ErrorEval.VALUE_INVALID;
} else {
StringBuffer strBuff = new StringBuffer(oldStr);
// remove any characters that should be replaced
if (startNum <= oldStr.length() && numChars != 0) {
strBuff.delete(startNum - 1, startNum - 1 + numChars);
}
// now insert (or append) newStr
if (startNum > strBuff.length()) {
strBuff.append(newStr);
} else {
strBuff.insert(startNum - 1, newStr);
}
retval = new StringEval(strBuff.toString());
}
}
return retval;
}
}

View File

@ -20,6 +20,98 @@
*/
package org.apache.poi.hssf.record.formula.functions;
public class Substitute 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.NumericValueEval;
import org.apache.poi.hssf.record.formula.eval.StringEval;
import org.apache.poi.hssf.record.formula.eval.StringValueEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
/**
* An implementation of the SUBSTITUTE function:
* Substitutes text in a text string with new text, some number of times.
* @author Manda Wilson &lt; wilson at c bio dot msk cc dot org &gt;
*/
public class Substitute extends TextFunction {
private static final int REPLACE_ALL = -1;
/**
*Substitutes text in a text string with new text, some number of times.
*
* @see org.apache.poi.hssf.record.formula.eval.Eval
*/
public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) {
Eval retval = null;
String oldStr = null;
String searchStr = null;
String newStr = null;
int numToReplace = REPLACE_ALL;
switch (operands.length) {
default:
retval = ErrorEval.VALUE_INVALID;
case 4:
ValueEval fourthveval = singleOperandEvaluate(operands[3], srcCellRow, srcCellCol);
if (fourthveval instanceof NumericValueEval) {
NumericValueEval numToReplaceEval = (NumericValueEval) fourthveval;
// NOTE: it is safe to cast to int here
// because in Excel =SUBSTITUTE("teststr","t","T",1.9)
// returns Teststr
// so 1.9 must be truncated to 1
numToReplace = (int) numToReplaceEval.getNumberValue();
} else {
retval = ErrorEval.VALUE_INVALID;
}
case 3:
// first operand is text string containing characters to replace
// second operand is text to find
// third operand is replacement text
ValueEval firstveval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol);
ValueEval secondveval = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol);
ValueEval thirdveval = singleOperandEvaluate(operands[2], srcCellRow, srcCellCol);
if (firstveval instanceof StringValueEval
&& secondveval instanceof StringValueEval
&& thirdveval instanceof StringValueEval) {
StringValueEval oldStrEval = (StringValueEval) firstveval;
oldStr = oldStrEval.getStringValue();
StringValueEval searchStrEval = (StringValueEval) secondveval;
searchStr = searchStrEval.getStringValue();
StringValueEval newStrEval = (StringValueEval) thirdveval;
newStr = newStrEval.getStringValue();
} else {
retval = ErrorEval.VALUE_INVALID;
}
}
if (retval == null) {
if (numToReplace != REPLACE_ALL && numToReplace < 1) {
retval = ErrorEval.VALUE_INVALID;
} else if (searchStr.length() == 0) {
retval = new StringEval(oldStr);
} else {
StringBuffer strBuff = new StringBuffer();
int startIndex = 0;
int nextMatch = -1;
for (int leftToReplace = numToReplace;
(leftToReplace > 0 || numToReplace == REPLACE_ALL)
&& (nextMatch = oldStr.indexOf(searchStr, startIndex)) != -1;
leftToReplace--) {
// store everything from end of last match to start of this match
strBuff.append(oldStr.substring(startIndex, nextMatch));
strBuff.append(newStr);
startIndex = nextMatch + searchStr.length();
}
// store everything from end of last match to end of string
if (startIndex < oldStr.length()) {
strBuff.append(oldStr.substring(startIndex));
}
retval = new StringEval(strBuff.toString());
}
}
return retval;
}
}