Skip to content

Added ExtractStringBetween and ToConvertedSequence #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
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
30 changes: 30 additions & 0 deletions src/ByteDev.Strings/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -223,5 +223,35 @@ public static string InsertBeforeUpperCase(this string source, string delimiter)

return sb.ToString();
}

/// <summary>
/// Extracts the string between the specified start and end string.
/// e.g. for "The quick brown fox jumps over the lazy dog", the string between "quick" and "jumps" is " brown fox ".
/// If there are multiple instances of a start or end string, it will use the first instance.
/// An empty string will be returned if no matches were found.
/// </summary>
/// <param name="source">String to perform the operation on.</param>
/// <param name="startString">The start string to find</param>
/// <param name="endString">The end string to find after the startString</param>
/// <param name="stringComparison">The string comparison to use (defaults to StringComparison.OrdinalIgnoreCase)</param>
/// <returns>The string in between startString and endString, or empty string if not found</returns>
public static string ExtractStringBetween(this string source, string startString, string endString, StringComparison stringComparison = StringComparison.OrdinalIgnoreCase)
{
if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(startString) || string.IsNullOrEmpty(endString))
return string.Empty;

var extractedString = string.Empty;
var startIndex = source.IndexOf(startString, stringComparison);

if (startIndex > -1)
{
startIndex += startString.Length;
var endIndex = source.IndexOf(endString, startIndex, stringComparison);
if (endIndex > -1)
extractedString = source.SafeSubstring(startIndex, endIndex - startIndex);
}

return extractedString;
}
}
}
26 changes: 26 additions & 0 deletions src/ByteDev.Strings/StringToExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -320,5 +320,31 @@ public static MemoryStream ToMemoryStream(this string source, Encoding encoding)

return new MemoryStream(bytes);
}

/// <summary>
/// Returns the string as a sequence with each value determined by the specified char delimiter, and converted to the specified type.
/// </summary>
/// <typeparam name="T">The type to convert each item into.</typeparam>
/// <param name="sourceString">The string to perform this operation on.</param>
/// <param name="delimiter">Value delimiter.</param>
/// <param name="trimValues">True trim each value; false do nothing.</param>
/// <returns>Collection of values; otherwise empty. Throws exception if values cannot be converted.</returns>
public static IEnumerable<T> ToConvertedSequence<T>(this string sourceString, char delimiter = ',', bool trimValues = false)
where T : struct, IConvertible
{
if (string.IsNullOrEmpty(sourceString))
return Enumerable.Empty<T>();

try
{
IEnumerable<string> stringValues = sourceString.ToSequence(delimiter, trimValues);

return stringValues.Select(stringValue => (T)Convert.ChangeType(stringValue, typeof(T)));
}
catch (Exception)
{
return Enumerable.Empty<T>();
}
}
}
}
46 changes: 45 additions & 1 deletion tests/ByteDev.Strings.UnitTests/StringExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -561,5 +561,49 @@ public void WhenHasUpperCase_ThenReturnString(string sut, string expected)
Assert.That(result, Is.EqualTo(expected));
}
}

[TestFixture]
public class ExtractStringBetween
{
[TestCase(null)]
[TestCase("")]
public void WhenSourceIsNullOrEmpty_ThenReturnEmptyString(string source)
{
var result = source.ExtractStringBetween("test1", "test2");

Assert.That(result, Is.EqualTo(string.Empty));
}

[TestCase("The quick brown fox jumps over the lazy dog", "quick1", "jumps")]
[TestCase("The quick brown fox jumps over the lazy dog", "the", "not found")]
public void WhenIsNotAMatchingSearch_ThenReturnEmptyString(string source, string startString, string endString)
{
var result = source.ExtractStringBetween(startString, endString);

Assert.That(result, Is.EqualTo(string.Empty));
}

[TestCase("The quick brown fox jumps over the lazy dog", "quick", "jumps", " brown fox ")]
[TestCase("The quick brown fox jumps over the lazy dog", "the", "dog", " quick brown fox jumps over the lazy ")]
[TestCase("The quick brown fox jumps over the lazy dog", "lazy", "dog", " ")]
[TestCase("<html><body><span id=\"test\">My test string</span></body></html>", "<span id=\"test\">", "</span>", "My test string")]
[TestCase("<html><body><span id=\"test-id\">My test string</span></body></html>", "<span id=\"", "\"", "test-id")]
public void WhenIsAMatchingSearch_ThenReturnExpectedValue(string source, string startString, string endString, string expected)
{
var result = source.ExtractStringBetween(startString, endString);

Assert.That(result, Is.EqualTo(expected));
}

[TestCase("The quick brown fox jumps over the lazy dog", "Quick", "jumps", "")]
[TestCase("The quick brown fox jumps over the lazy dog", "the", "dog", " lazy ")]
[TestCase("The quick brown fox jumps over the lazy dog", "lazy", "Dog", "")]
public void WhenIsACaseSensitiveMatchingSearch_ThenReturnExpectedValue(string source, string startString, string endString, string expected)
{
var result = source.ExtractStringBetween(startString, endString, StringComparison.Ordinal);

Assert.That(result, Is.EqualTo(expected));
}
}
}
}
}
48 changes: 48 additions & 0 deletions tests/ByteDev.Strings.UnitTests/StringToExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -721,5 +721,53 @@ public void WhenNotEmpty_ThenReturnStream()
Assert.That(result.ReadAsString(), Is.EqualTo(sut));
}
}

[TestFixture]
public class ToConvertedSequence
{
[TestCase(null)]
[TestCase("")]
public void WhenIsNullOrEmpty_ThenReturnEmptyList(string sut)
{
var result = sut.ToConvertedSequence<byte>();

Assert.IsNotNull(result);
Assert.That(result.Count(), Is.EqualTo(0));
}

[TestCase("1")]
[TestCase("489")]
[TestCase("2147483647")]
public void WhenDoesNotContainDelimiter_ThenReturnListWithOneValue(string sut)
{
var result = sut.ToConvertedSequence<int>();

Assert.IsNotNull(result);
var resultAsList = result.ToList();
Assert.That(resultAsList.Count, Is.EqualTo(1));
Assert.That(resultAsList[0], Is.EqualTo(Convert.ToInt32(sut)));
}

[TestCase("1,444,44", ',')]
[TestCase("89,092,7,9", ',')]
[TestCase("0:7", ':')]
[TestCase("8?99?5432?900", '?')]
public void WhenContainsDelimiter_ThenReturnListWithValues(string sut, char delimiter)
{
var expected = sut.Split(delimiter).Select(s => Convert.ToInt64(s));
var result = sut.ToConvertedSequence<long>(delimiter);

Assert.IsNotNull(result);
Assert.That(result, Is.EqualTo(expected));
}

[TestCase("abc", ',')]
[TestCase("1,444,44", ':')]
[TestCase("0:7", ',')]
public void WhenInvalidValues_ThenThrowException(string sut, char delimiter)
{
Assert.Throws<FormatException>(() => sut.ToConvertedSequence<short>(delimiter).ToList(), "Input string was not in a correct format.");
}
}
}
}