Skip to content
This repository was archived by the owner on Mar 9, 2020. It is now read-only.
Open
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
35 changes: 35 additions & 0 deletions EPPlus/FormulaParsing/Excel/Functions/ExcelFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,41 @@ protected void ValidateArguments(IEnumerable<FunctionArgument> arguments, int mi
return true;
}, "Expecting at least {0} arguments", minLength.ToString());
}


/// <summary>
/// This functions validates that the supplied <paramref name="arguments"/> contains at least
/// (the value of) <paramref name="minLength"/> elements. If one of the arguments is an
/// <see cref="ExcelDataProvider.IRangeInfo">Excel range</see> the number of cells in
/// that range will be counted as well.
/// </summary>
/// <param name="arguments"></param>
/// <param name="minLength"></param>
/// <param name="length"></param>
/// <exception cref="ArgumentException"></exception>
protected void ValidateArguments(IEnumerable<FunctionArgument> arguments, int minLength, out int length)
{
Require.That(arguments).Named("arguments").IsNotNull();
var nArgs = 0;
ThrowArgumentExceptionIf(() =>
{
if (arguments.Any())
{
foreach (var arg in arguments)
{
nArgs++;
if (arg.IsExcelRange)
{
nArgs += arg.ValueAsRangeInfo.GetNCells();
}
}
if (nArgs >= minLength) return false;
}
return true;
}, "Expecting at least {0} arguments", minLength.ToString());
length = nArgs;
}

protected string ArgToAddress(IEnumerable<FunctionArgument> arguments, int index)
{
return arguments.ElementAt(index).IsExcelRange ? arguments.ElementAt(index).ValueAsRangeInfo.Address.FullAddress : ArgToString(arguments, index);
Expand Down
36 changes: 34 additions & 2 deletions EPPlus/FormulaParsing/Excel/Functions/Text/Substitute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,44 @@ public class Substitute : ExcelFunction
{
public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context)
{
ValidateArguments(arguments, 3);
int argCount;
ValidateArguments(arguments, 3, out argCount);
var text = ArgToString(arguments, 0);
var find = ArgToString(arguments, 1);
var replaceWith = ArgToString(arguments, 2);
var result = text.Replace(find, replaceWith);
string result;
if (argCount > 3)
{
var instanceNum = ArgToInt(arguments, 3);
result = ReplaceFirst(text, find, replaceWith, instanceNum);
}
else
{
result = text.Replace(find, replaceWith);
}
return CreateResult(result, DataType.String);
}

/// <summary>
/// Replaces only the Nth instance of substring.
/// </summary>
/// <param name="text">String to modify</param>
/// <param name="search">Substring to look for</param>
/// <param name="replace">Replacement for the matched substring</param>
/// <param name="instanceNumber">One-based index of match to replace</param>
/// <returns>Modified copy of parameter text where only the specified substring instance has been replaced</returns>
private static string ReplaceFirst(string text, string search, string replace, int instanceNumber)
{
int pos = -1;
for (int i=0; i<instanceNumber; i++)
{
pos = text.IndexOf(search, pos+1);
}
if (pos < 0)
{
return text;
}
return text.Substring(0, pos) + replace + text.Substring(pos + search.Length);
}
}
}
16 changes: 16 additions & 0 deletions EPPlusTest/FormulaParsing/Excel/Functions/TextFunctionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,22 @@ public void SubstituteShouldReturnAReplacedStringAccordingToParamsWhen()
Assert.AreEqual("txxtar txxtar", result.Result);
}

[TestMethod]
public void SubstituteShouldReplaceOnlyFirstInstance()
{
var func = new Substitute();
var result = func.Execute(FunctionsHelper.CreateArgs("testar testar", "es", "xx", 1), _parsingContext);
Assert.AreEqual("txxtar testar", result.Result);
}

[TestMethod]
public void SubstituteShouldReplaceOnlySecondInstance()
{
var func = new Substitute();
var result = func.Execute(FunctionsHelper.CreateArgs("testar testar", "es", "xx", 2), _parsingContext);
Assert.AreEqual("testar txxtar", result.Result);
}

[TestMethod]
public void ConcatenateShouldConcatenateThreeStrings()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ public void SubstituteShouldReturnSubstringAccordingToParams()
Assert.AreEqual("txxtar txxtar", result);
}

[TestMethod]
public void SubstituteShouldReplaceOnlySecondInstanceFound()
{
var result = _parser.Parse("Substitute(\"testar testar\", \"es\", \"xx\", 2)");
Assert.AreEqual("testar txxtar", result);
}

[TestMethod]
public void ConcatenateShouldReturnAccordingToParams()
{
Expand Down