U4-2635 Skip past replaced word when checking

Avoids infinite loop if search and replacement are equal
This commit is contained in:
Shannon
2014-04-30 11:21:12 +10:00
parent d33cc29f98
commit 771e216813
2 changed files with 20 additions and 7 deletions

View File

@@ -1123,17 +1123,18 @@ namespace Umbraco.Core
/// <returns>Updated string</returns>
public static string Replace(this string source, string oldString, string newString, StringComparison stringComparison)
{
var index = source.IndexOf(oldString, stringComparison);
// This initialisation ensures the first check starts at index zero of the source. On successive checks for
// a match, the source is skipped to immediately after the last replaced occurrence for efficiency
// and to avoid infinite loops when oldString and newString compare equal.
int index = -1 * newString.Length;
// Determine if we found a match
var matchFound = index >= 0;
if (matchFound)
// Determine if there are any matches left in source, starting from just after the result of replacing the last match.
while((index = source.IndexOf(oldString, index + newString.Length, stringComparison)) >= 0)
{
// Remove the old text
// Remove the old text.
source = source.Remove(index, oldString.Length);
// Add the replacemenet text
// Add the replacemenet text.
source = source.Insert(index, newString);
}

View File

@@ -80,6 +80,18 @@ namespace Umbraco.Tests.CoreStrings
Assert.AreEqual(shouldBe, trimmed);
}
[TestCase("Hello this is my string", "hello", "replaced", "replaced this is my string", StringComparison.CurrentCultureIgnoreCase)]
[TestCase("Hello this is hello my string", "hello", "replaced", "replaced this is replaced my string", StringComparison.CurrentCultureIgnoreCase)]
[TestCase("Hello this is my string", "nonexistent", "replaced", "Hello this is my string", StringComparison.CurrentCultureIgnoreCase)]
[TestCase("Hellohello this is my string", "hello", "replaced", "replacedreplaced this is my string", StringComparison.CurrentCultureIgnoreCase)]
// Ensure replacing with the same string doesn't cause infinite loop.
[TestCase("Hello this is my string", "hello", "hello", "hello this is my string", StringComparison.CurrentCultureIgnoreCase)]
public void ReplaceWithStringComparison(string input, string oldString, string newString, string shouldBe, StringComparison stringComparison)
{
var replaced = input.Replace(oldString, newString, stringComparison);
Assert.AreEqual(shouldBe, replaced);
}
[TestCase(null, null)]
[TestCase("", "")]
[TestCase("x", "X")]