Skip to content

Commit

Permalink
Merge pull request #1287 from superrnovae/text_function
Browse files Browse the repository at this point in the history
[Bug-67475] Better support for edge cases in TEXT function.
  • Loading branch information
tonyqus authored May 3, 2024
2 parents e7067a7 + bc1e075 commit 09966aa
Show file tree
Hide file tree
Showing 7 changed files with 353 additions and 238 deletions.
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

0 comments on commit 09966aa

Please sign in to comment.