Add CountSubstring

This commit is contained in:
Oliver Booth 2022-11-26 09:31:36 +00:00
parent 3847d53120
commit 9cce13727d
No known key found for this signature in database
GPG Key ID: 32A00B35503AF634
3 changed files with 208 additions and 0 deletions

View File

@ -28,10 +28,16 @@
- X10D: Added `PointF.ToSizeF()` - X10D: Added `PointF.ToSizeF()`
- X10D: Added `PointF.ToVector2()` for .NET < 6 - X10D: Added `PointF.ToVector2()` for .NET < 6
- X10D: Added `PopCount()` for built-in integer types - X10D: Added `PopCount()` for built-in integer types
- X10D: Added `ReadOnlySpan<char>.CountSubstring(char)`
- X10D: Added `ReadOnlySpan<char>.CountSubstring(ReadOnlySpan<char>[, StringComparison])`
- X10D: Added `RoundUpToPowerOf2()` for built-in integer types - X10D: Added `RoundUpToPowerOf2()` for built-in integer types
- X10D: Added `Size.ToPoint()` - X10D: Added `Size.ToPoint()`
- X10D: Added `Size.ToPointF()` - X10D: Added `Size.ToPointF()`
- X10D: Added `Size.ToVector2()` - X10D: Added `Size.ToVector2()`
- X10D: Added `Span<char>.CountSubstring(char)`
- X10D: Added `Span<char>.CountSubstring(Span<char>[, StringComparison])`
- X10D: Added `string.CountSubstring(char)`
- X10D: Added `string.CountSubstring(string[, StringComparison])`
- X10D: Added `Quaternion.Multiply(Vector3)` - this functions as an equivalent to Unity's `Quaternion * Vector3` operator - X10D: Added `Quaternion.Multiply(Vector3)` - this functions as an equivalent to Unity's `Quaternion * Vector3` operator
- X10D: Added `Vector2.Deconstruct()` - X10D: Added `Vector2.Deconstruct()`
- X10D: Added `Vector2.IsOnLine(LineF)`, `Vector2.IsOnLine(PointF, PointF)`, and `Vector2.IsOnLine(Vector2, Vector2)` - X10D: Added `Vector2.IsOnLine(LineF)`, `Vector2.IsOnLine(PointF, PointF)`, and `Vector2.IsOnLine(Vector2, Vector2)`

View File

@ -101,6 +101,55 @@ public class StringTests
Assert.ThrowsException<ArgumentNullException>(() => "Hello World".ChangeEncoding(Encoding.UTF8, null!)); Assert.ThrowsException<ArgumentNullException>(() => "Hello World".ChangeEncoding(Encoding.UTF8, null!));
} }
[TestMethod]
public void CountSubstring_ShouldHonor_StringComparison()
{
Assert.AreEqual(0, "Hello World".CountSubstring('E'));
Assert.AreEqual(0, "Hello World".CountSubstring("E"));
Assert.AreEqual(1, "Hello World".CountSubstring("E", StringComparison.OrdinalIgnoreCase));
Assert.AreEqual(0, "Hello World".AsSpan().CountSubstring('E'));
Assert.AreEqual(1, "Hello World".AsSpan().CountSubstring("E".AsSpan(), StringComparison.OrdinalIgnoreCase));
}
[TestMethod]
public void CountSubstring_ShouldReturn0_GivenNoInstanceChar()
{
Assert.AreEqual(0, "Hello World".CountSubstring('z'));
Assert.AreEqual(0, "Hello World".CountSubstring("z"));
Assert.AreEqual(0, "Hello World".CountSubstring("z", StringComparison.OrdinalIgnoreCase));
Assert.AreEqual(0, "Hello World".AsSpan().CountSubstring('z'));
Assert.AreEqual(0, "Hello World".AsSpan().CountSubstring("z".AsSpan(), StringComparison.OrdinalIgnoreCase));
}
[TestMethod]
public void CountSubstring_ShouldReturn1_GivenSingleInstanceChar()
{
Assert.AreEqual(1, "Hello World".CountSubstring('e'));
Assert.AreEqual(1, "Hello World".CountSubstring("e"));
Assert.AreEqual(1, "Hello World".CountSubstring("e", StringComparison.OrdinalIgnoreCase));
Assert.AreEqual(1, "Hello World".AsSpan().CountSubstring('e'));
Assert.AreEqual(1, "Hello World".AsSpan().CountSubstring("e".AsSpan(), StringComparison.OrdinalIgnoreCase));
}
[TestMethod]
public void CountSubstring_ShouldReturn0_GivenEmptyHaystack()
{
Assert.AreEqual(0, string.Empty.CountSubstring('\0'));
Assert.AreEqual(0, string.Empty.CountSubstring(string.Empty));
Assert.AreEqual(0, string.Empty.CountSubstring(string.Empty, StringComparison.OrdinalIgnoreCase));
Assert.AreEqual(0, string.Empty.AsSpan().CountSubstring('\0'));
Assert.AreEqual(0, string.Empty.AsSpan().CountSubstring(string.Empty.AsSpan(), StringComparison.OrdinalIgnoreCase));
}
[TestMethod]
public void CountSubstring_ShouldThrow_GivenNullHaystack()
{
Assert.ThrowsException<ArgumentNullException>(() => ((string?)null!).CountSubstring('\0'));
Assert.ThrowsException<ArgumentNullException>(() => ((string?)null!).CountSubstring(string.Empty));
Assert.ThrowsException<ArgumentNullException>(() =>
((string?)null!).CountSubstring(string.Empty, StringComparison.OrdinalIgnoreCase));
}
[TestMethod] [TestMethod]
public void EnumParse_ShouldReturnCorrectValue_GivenString() public void EnumParse_ShouldReturnCorrectValue_GivenString()
{ {

View File

@ -162,6 +162,159 @@ public static class StringExtensions
return value.GetBytes(sourceEncoding).ToString(destinationEncoding); return value.GetBytes(sourceEncoding).ToString(destinationEncoding);
} }
/// <summary>
/// Counts the occurrences of a character within the current character span.
/// </summary>
/// <param name="haystack">The haystack search space.</param>
/// <param name="needle">The character to count.</param>
/// <returns>An integer representing the count of <paramref name="needle" /> inside <paramref name="haystack" />.</returns>
public static int CountSubstring(this Span<char> haystack, char needle)
{
return CountSubstring((ReadOnlySpan<char>)haystack, needle);
}
/// <summary>
/// Counts the occurrences of a character within the current character span.
/// </summary>
/// <param name="haystack">The haystack search space.</param>
/// <param name="needle">The character to count.</param>
/// <returns>An integer representing the count of <paramref name="needle" /> inside <paramref name="haystack" />.</returns>
public static int CountSubstring(this ReadOnlySpan<char> haystack, char needle)
{
var count = 0;
for (var index = 0; index < haystack.Length; index++)
{
if (haystack[index] == needle)
{
count++;
}
}
return count;
}
/// <summary>
/// Counts the occurrences of a character within the current string.
/// </summary>
/// <param name="haystack">The haystack search space.</param>
/// <param name="needle">The character to count.</param>
/// <returns>An integer representing the count of <paramref name="needle" /> inside <paramref name="haystack" />.</returns>
public static int CountSubstring(this string haystack, char needle)
{
#if NET6_0_OR_GREATER
ArgumentNullException.ThrowIfNull(haystack);
#else
if (haystack is null)
{
throw new ArgumentNullException(nameof(haystack));
}
#endif
return haystack.AsSpan().CountSubstring(needle);
}
/// <summary>
/// Counts the occurrences of a substring within the current character span.
/// </summary>
/// <param name="haystack">The haystack search space.</param>
/// <param name="needle">The character span to count.</param>
/// <returns>An integer representing the count of <paramref name="needle" /> inside <paramref name="haystack" />.</returns>
public static int CountSubstring(this ReadOnlySpan<char> haystack, ReadOnlySpan<char> needle)
{
return CountSubstring(haystack, needle, StringComparison.Ordinal);
}
/// <summary>
/// Counts the occurrences of a substring within the current character span, using a specified string comparison method.
/// </summary>
/// <param name="haystack">The haystack search space.</param>
/// <param name="needle">The character span to count.</param>
/// <param name="comparison">The string comparison method used for determining substring count.</param>
/// <returns>An integer representing the count of <paramref name="needle" /> inside <paramref name="haystack" />.</returns>
public static int CountSubstring(this ReadOnlySpan<char> haystack, ReadOnlySpan<char> needle, StringComparison comparison)
{
if (haystack.IsEmpty || needle.IsEmpty)
{
return 0;
}
int haystackLength = haystack.Length;
int needleLength = needle.Length;
var count = 0;
for (var index = 0; index < haystackLength - needleLength - 1; index++)
{
if (haystack[index..(index + needleLength)].Equals(needle, comparison))
{
count++;
}
}
return count;
}
/// <summary>
/// Counts the occurrences of a substring within the current character span.
/// </summary>
/// <param name="haystack">The haystack search space.</param>
/// <param name="needle">The character span to count.</param>
/// <returns>An integer representing the count of <paramref name="needle" /> inside <paramref name="haystack" />.</returns>
public static int CountSubstring(this Span<char> haystack, Span<char> needle)
{
return CountSubstring(haystack, needle, StringComparison.Ordinal);
}
/// <summary>
/// Counts the occurrences of a substring within the current character span, using a specified string comparison method.
/// </summary>
/// <param name="haystack">The haystack search space.</param>
/// <param name="needle">The character span to count.</param>
/// <param name="comparison">The string comparison method used for determining substring count.</param>
/// <returns>An integer representing the count of <paramref name="needle" /> inside <paramref name="haystack" />.</returns>
public static int CountSubstring(this Span<char> haystack, Span<char> needle, StringComparison comparison)
{
return CountSubstring((ReadOnlySpan<char>)haystack, needle, comparison);
}
/// <summary>
/// Counts the occurrences of a substring within the current string.
/// </summary>
/// <param name="haystack">The haystack search space.</param>
/// <param name="needle">The substring to count.</param>
/// <returns>An integer representing the count of <paramref name="needle" /> inside <paramref name="haystack" />.</returns>
public static int CountSubstring(this string haystack, string? needle)
{
return CountSubstring(haystack, needle, StringComparison.Ordinal);
}
/// <summary>
/// Counts the occurrences of a substring within the current string, using a specified string comparison method.
/// </summary>
/// <param name="haystack">The haystack search space.</param>
/// <param name="needle">The substring to count.</param>
/// <param name="comparison">The string comparison method used for determining substring count.</param>
/// <returns>An integer representing the count of <paramref name="needle" /> inside <paramref name="haystack" />.</returns>
public static int CountSubstring(this string haystack, string? needle, StringComparison comparison)
{
#if NET6_0_OR_GREATER
ArgumentNullException.ThrowIfNull(haystack);
#else
if (haystack is null)
{
throw new ArgumentNullException(nameof(haystack));
}
#endif
if (string.IsNullOrWhiteSpace(needle))
{
return 0;
}
return haystack.AsSpan().CountSubstring(needle, comparison);
}
/// <summary> /// <summary>
/// Parses a <see cref="string" /> into an <see cref="Enum" />. /// Parses a <see cref="string" /> into an <see cref="Enum" />.
/// </summary> /// </summary>