Skip to content

Commit

Permalink
Remove exception from FIND function.
Browse files Browse the repository at this point in the history
  • Loading branch information
jahav committed Feb 18, 2023
1 parent a98d0bb commit 8dc0e70
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 24 deletions.
74 changes: 64 additions & 10 deletions ClosedXML.Tests/Excel/CalcEngine/TextTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -179,42 +179,96 @@ public void Exact_Value()
Assert.AreEqual(false, actual);
}

[Test]
public void Find_Empty_Pattern_And_Empty_Text()
{
// Different behavior from SEARCH
Assert.AreEqual(1, XLWorkbook.EvaluateExpr(@"FIND("""", """")"));

Assert.AreEqual(2, XLWorkbook.EvaluateExpr(@"FIND("""", ""a"", 2)"));
}

[Test]
public void Find_Empty_Search_Pattern_Returns_Start_Of_Text()
{
Assert.AreEqual(1, XLWorkbook.EvaluateExpr(@"FIND("""", ""asdf"")"));
}

[Test]
public void Find_Looks_Only_From_Start_Position_Onward()
{
Assert.AreEqual(XLError.IncompatibleValue, XLWorkbook.EvaluateExpr(@"FIND(""This"", ""This is some text"", 2)"));
}

[Test]
public void Find_Start_Position_Too_Large()
{
Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""abc"", ""abcdef"", 10)"), Throws.TypeOf<ArgumentOutOfRangeException>());
Assert.AreEqual(XLError.IncompatibleValue, XLWorkbook.EvaluateExpr(@"FIND(""abc"", ""abcdef"", 10)"));
}

[Test]
public void Find_Start_Position_Too_Small()
{
Assert.AreEqual(XLError.IncompatibleValue, XLWorkbook.EvaluateExpr(@"FIND(""text"", ""This is some text"", 0)"));
}

[Test]
public void Find_String_In_Another_Empty_String()
public void Find_Empty_Searched_Text_Returns_Error()
{
Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""abc"", """")"), Throws.TypeOf<ArgumentException>());
Assert.AreEqual(XLError.IncompatibleValue, XLWorkbook.EvaluateExpr(@"FIND(""abc"", """")"));
}

[Test]
public void Find_String_Not_Found()
{
Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""123"", ""asdf"")"), Throws.TypeOf<ArgumentException>());
Assert.AreEqual(XLError.IncompatibleValue, XLWorkbook.EvaluateExpr(@"FIND(""123"", ""asdf"")"));
}

[Test]
public void Find_Case_Sensitive_String_Not_Found()
{
// Find is case-sensitive
Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""excel"", ""Microsoft Excel 2010"")"), Throws.TypeOf<ArgumentException>());
Assert.AreEqual(XLError.IncompatibleValue, XLWorkbook.EvaluateExpr(@"FIND(""excel"", ""Microsoft Excel 2010"")"));
}

[Test]
public void Find_Value()
{
Object actual = XLWorkbook.EvaluateExpr(@"Find(""Tuesday"", ""Today is Tuesday"")");
var actual = XLWorkbook.EvaluateExpr(@"FIND(""Tuesday"", ""Today is Tuesday"")");
Assert.AreEqual(10, actual);

actual = XLWorkbook.EvaluateExpr(@"Find("""", """")");
Assert.AreEqual(1, actual);
// Doesnt support wildcards
actual = XLWorkbook.EvaluateExpr(@"FIND(""T*y"", ""Today is Tuesday"")");
Assert.AreEqual(XLError.IncompatibleValue, actual);
}

actual = XLWorkbook.EvaluateExpr(@"Find("""", ""asdf"")");
Assert.AreEqual(1, actual);
[Test]
public void Find_Arguments_Are_Converted_To_Expected_Types()
{
var actual = XLWorkbook.EvaluateExpr(@"FIND(1.2, ""A1.2B"")");
Assert.AreEqual(2, actual);

actual = XLWorkbook.EvaluateExpr(@"FIND(TRUE, ""ATRUE"")");
Assert.AreEqual(2, actual);

actual = XLWorkbook.EvaluateExpr(@"FIND(23, 1.2345)");
Assert.AreEqual(3, actual);

actual = XLWorkbook.EvaluateExpr(@"FIND(""a"", ""aaaaa"", ""2 1/2"")");
Assert.AreEqual(2, actual);
}

[Test]
public void Find_Error_Arguments_Return_The_Error()
{
var actual = XLWorkbook.EvaluateExpr(@"FIND(#N/A, ""a"")");
Assert.AreEqual(XLError.NoValueAvailable, actual);

actual = XLWorkbook.EvaluateExpr(@"FIND("""", #N/A)");
Assert.AreEqual(XLError.NoValueAvailable, actual);

actual = XLWorkbook.EvaluateExpr(@"FIND(""a"", ""a"", #N/A)");
Assert.AreEqual(XLError.NoValueAvailable, actual);
}

[Test]
Expand Down
25 changes: 11 additions & 14 deletions ClosedXML/Excel/CalcEngine/Functions/Text.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public static void Register(FunctionRegistry ce)
ce.RegisterFunction("CONCATENATE", 1, int.MaxValue, Concatenate, AllowRange.All); // Joins several text items into one text item
ce.RegisterFunction("DOLLAR", 1, 2, Dollar); // Converts a number to text, using the $ (dollar) currency format
ce.RegisterFunction("EXACT", 2, Exact); // Checks to see if two text values are identical
ce.RegisterFunction("FIND", 2, 3, Find); //Finds one text value within another (case-sensitive)
ce.RegisterFunction("FIND", 2, 3, AdaptLastOptional(Find), FunctionFlags.Scalar); //Finds one text value within another (case-sensitive)
ce.RegisterFunction("FIXED", 1, 3, Fixed); // Formats a number as text with a fixed number of decimals
//ce.RegisterFunction("JIS Changes half-width (single-byte) English letters or katakana within a character string to full-width (double-byte) characters
ce.RegisterFunction("LEFT", 1, 2, Left); // LEFTB Returns the leftmost characters from a text value
Expand Down Expand Up @@ -106,20 +106,17 @@ private static object Concatenate(List<Expression> p)
return sb.ToString();
}

private static object Find(List<Expression> p)
private static AnyValue Find(CalcContext ctx, String findText, String withinText, OneOf<double, Blank> startNum)
{
var srch = (string)p[0];
var text = (string)p[1];
var start = 0;
if (p.Count > 2)
{
start = (int)p[2] - 1;
}
var index = text.IndexOf(srch, start, StringComparison.Ordinal);
if (index == -1)
throw new ArgumentException("String not found.");
else
return index + 1;
var startIndex = startNum.TryPickT0(out var startNumber, out _) ? (int)Math.Truncate(startNumber) - 1 : 0;
if (startIndex < 0 || startIndex > withinText.Length)
return XLError.IncompatibleValue;

var text = withinText.AsSpan(startIndex);
var index = text.IndexOf(findText.AsSpan());
return index == -1
? XLError.IncompatibleValue
: index + startIndex + 1;
}

private static object Left(List<Expression> p)
Expand Down

0 comments on commit 8dc0e70

Please sign in to comment.