Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[POI-Bug-67475] Better support for edge cases in TEXT function. #1287

Merged
merged 1 commit into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 49 additions & 84 deletions main/SS/Formula/Eval/OperandResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ public class OperandResolver
{
// Based on regular expression defined in JavaDoc at {@link java.lang.Double#valueOf}
// modified to remove support for NaN, Infinity, Hexadecimal support and floating type suffixes
private const String Digits = "\\d+";
private const String Exp = "[eE][+-]?" + Digits;
private const String fpRegex =
private const string Digits = "\\d+";
private const string Exp = "[eE][+-]?" + Digits;
private const string fpRegex =
("[\\x00-\\x20]*" +
"[+-]?(" +
"(((" + Digits + "(\\.)?(" + Digits + "?)(" + Exp + ")?)|" +
Expand All @@ -58,21 +58,21 @@ private OperandResolver()
public static ValueEval GetSingleValue(ValueEval arg, int srcCellRow, int srcCellCol)
{
ValueEval result;
if (arg is RefEval)
if (arg is RefEval rev)
{
result = ChooseSingleElementFromRef((RefEval)arg);
result = ChooseSingleElementFromRef(rev);
}
else if (arg is AreaEval)
else if (arg is AreaEval aev)
{
result = ChooseSingleElementFromArea((AreaEval)arg, srcCellRow, srcCellCol);
result = ChooseSingleElementFromArea(aev, srcCellRow, srcCellCol);
}
else
{
result = arg;
}
if (result is ErrorEval)
if (result is ErrorEval eva)
{
throw new EvaluationException((ErrorEval)result);
throw new EvaluationException(eva);
}
return result;
}
Expand Down Expand Up @@ -126,9 +126,9 @@ public static ValueEval ChooseSingleElementFromArea(AreaEval ae,
{
ValueEval result = ChooseSingleElementFromAreaInternal(ae, srcCellRow, srcCellCol);

if (result is ErrorEval)
if (result is ErrorEval eva)
{
throw new EvaluationException((ErrorEval)result);
throw new EvaluationException(eva);

}
return result;
Expand Down Expand Up @@ -236,14 +236,14 @@ public static double CoerceValueToDouble(ValueEval ev)
{
return 0.0;
}
if (ev is NumericValueEval)
if (ev is NumericValueEval nve)
{
// this also handles bools
return ((NumericValueEval)ev).NumberValue;
return nve.NumberValue;
}
if (ev is StringEval)
if (ev is StringEval sev)
{
double dd = ParseDouble(((StringEval)ev).StringValue);
double dd = ParseDouble(sev.StringValue);
if (double.IsNaN(dd))
{
throw EvaluationException.InvalidValue();
Expand All @@ -269,64 +269,29 @@ public static double CoerceValueToDouble(ValueEval ev)
* @param text
* @return <c>null</c> if the specified text cannot be Parsed as a number
*/
public static double ParseDouble(String pText)
public static double ParseDouble(string pText)
{
//if (Regex.Match(fpRegex, pText).Success)
try
{
double ret = double.Parse(pText, CultureInfo.CurrentCulture);
if (double.IsInfinity(ret))
return double.NaN;
return ret;
}
catch
{
return Double.NaN;
}
//else
try
{
//return Double.NaN;
double ret = double.Parse(pText, CultureInfo.CurrentCulture);
if (double.IsInfinity(ret))
return double.NaN;
return ret;
}
catch
{
return double.NaN;
}
//String text = pText.Trim();
//if (text.Length < 1)
//{
// return double.NaN;
//}
//bool isPositive = true;
//if (text[0] == '-')
//{
// isPositive = false;
// text = text.Substring(1).Trim();
//}

//if (text.Length == 0 || !Char.IsDigit(text[0]))
//{
// // avoid using Exception to tell when string is not a number
// return double.NaN;
//}
//// TODO - support notation like '1E3' (==1000)

//double val;
//try
//{
// val = double.Parse(text);
//}
//catch
//{
// return double.NaN;
//}
//return isPositive ? +val : -val;
}

/**
* @param ve must be a <c>NumberEval</c>, <c>StringEval</c>, <c>BoolEval</c>, or <c>BlankEval</c>
* @return the Converted string value. never <c>null</c>
*/
public static String CoerceValueToString(ValueEval ve)
public static string CoerceValueToString(ValueEval ve)
{
if (ve is StringValueEval)
if (ve is StringValueEval sve)
{
StringValueEval sve = (StringValueEval)ve;
return sve.StringValue;
}

Expand All @@ -336,30 +301,31 @@ public static String CoerceValueToString(ValueEval ve)
}
throw new ArgumentException("Unexpected eval class (" + ve.GetType().Name + ")");
}

/**
* @return <c>null</c> to represent blank values
* @throws EvaluationException if ve is an ErrorEval, or if a string value cannot be converted
*/
public static Boolean? CoerceValueToBoolean(ValueEval ve, bool stringsAreBlanks)
* @return <c>null</c> to represent blank values
* @throws EvaluationException if ve is an ErrorEval, or if a string value cannot be converted
*/
public static bool? CoerceValueToBoolean(ValueEval ve, bool stringsAreBlanks)
{

if (ve == null || ve == BlankEval.instance)
{
// TODO - remove 've == null' condition once AreaEval is fixed
return null;
}
if (ve is BoolEval)
if (ve is BoolEval be)
{
return ((BoolEval)ve).BooleanValue;
return be.BooleanValue;
}

if (ve is StringEval)
if (ve is StringEval se)
{
if (stringsAreBlanks)
{
return null;
}
String str = ((StringEval)ve).StringValue;
string str = se.StringValue;
if (str.Equals("true", StringComparison.OrdinalIgnoreCase))
{
return true;
Expand All @@ -372,32 +338,31 @@ public static String CoerceValueToString(ValueEval ve)
throw new EvaluationException(ErrorEval.VALUE_INVALID);
}

if (ve is NumericValueEval)
if(ve is NumericValueEval ne)
{
NumericValueEval ne = (NumericValueEval)ve;
double d = ne.NumberValue;
if (Double.IsNaN(d))
if(double.IsNaN(d))
{
throw new EvaluationException(ErrorEval.VALUE_INVALID);
}
return d != 0;
}
if (ve is ErrorEval)
if (ve is ErrorEval ee)
{
throw new EvaluationException((ErrorEval)ve);
throw new EvaluationException(ee);
}
throw new InvalidOperationException("Unexpected eval (" + ve.GetType().Name + ")");
}
/**
* Retrieves a single value from an area evaluation utilizing the 2D indices of the cell
* within its own area reference to index the value in the area evaluation.
*
* @param ae area reference after evaluation
* @param cell the source cell of the formula that contains its 2D indices
* @return a <tt>NumberEval</tt>, <tt>StringEval</tt>, <tt>BoolEval</tt> or <tt>BlankEval</tt>. or <tt>ErrorEval<tt>
* Never <code>null</code>.
*/

/**
* Retrieves a single value from an area evaluation utilizing the 2D indices of the cell
* within its own area reference to index the value in the area evaluation.
*
* @param ae area reference after evaluation
* @param cell the source cell of the formula that contains its 2D indices
* @return a <tt>NumberEval</tt>, <tt>StringEval</tt>, <tt>BoolEval</tt> or <tt>BlankEval</tt>. or <tt>ErrorEval<tt>
* Never <code>null</code>.
*/
public static ValueEval GetElementFromArray(AreaEval ae, IEvaluationCell cell)
{
CellRangeAddress range = cell.ArrayFormulaRange;
Expand Down
14 changes: 5 additions & 9 deletions main/SS/Formula/Eval/StringEval.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,27 +30,23 @@ public class StringEval : StringValueEval
{
public static readonly StringEval EMPTY_INSTANCE = new StringEval("");

private String value;
private readonly string value;

public StringEval(Ptg ptg):this(((StringPtg)ptg).Value)
{

}

public StringEval(String value)
public StringEval(string value)
{
if (value == null)
{
throw new ArgumentException("value must not be null");
}
this.value = value;
this.value = value ?? throw new ArgumentException("value must not be null");
}

public String StringValue
public string StringValue
{
get { return value; }
}
public override String ToString()
public override string ToString()
{
StringBuilder sb = new StringBuilder(64);
sb.Append(GetType().Name).Append(" [");
Expand Down
4 changes: 2 additions & 2 deletions main/SS/Formula/Functions/Text/Exact.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ public override ValueEval EvaluateFunc(ValueEval[] args, int srcCellRow, int src
return ErrorEval.VALUE_INVALID;
}

String s0 = EvaluateStringArg(args[0], srcCellRow, srcCellCol);
String s1 = EvaluateStringArg(args[1], srcCellRow, srcCellCol);
string s0 = EvaluateStringArg(args[0], srcCellRow, srcCellCol);
string s1 = EvaluateStringArg(args[1], srcCellRow, srcCellCol);
return BoolEval.ValueOf(s0.Equals(s1));
}
}
Expand Down
Loading
Loading