Skip to content

Commit

Permalink
Added SpanBetweenLast & bumped version.
Browse files Browse the repository at this point in the history
  • Loading branch information
db2222 committed Aug 22, 2023
1 parent 27eb467 commit 7774686
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 4 deletions.
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,21 +133,37 @@ span | startText | endText | Return value
-----|-----------|---------|-------------
`<td>Dummy1</td><td>Dummy2</td>` | `<td>` | `</td>` | `<td>Dummy1</td><td>Dummy2</td>`

## SpanBetweenLast
Returns all characters between the last occurence of the given start and end text.

### Example
span | startText | endText | Return value
-----|-----------|---------|-------------
`<td>Dummy1</td><td>Dummy2</td>` | `<td>` | `</td>` | `Dummy2`

## SpanBetweenLastIncluding
Returns all characters between the last occurence of the given start and end text and including the texts themselves.

### Example
span | startText | endText | Return value
-----|-----------|---------|-------------
`<td>Dummy1</td><td>Dummy2</td>` | `<td>` | `</td>` | `<td>Dummy2</td>`

## SpanBetweenNth
Returns all characters between the nth occurence of the given start and end text.

### Example
span | startText | endText | count | Return value
-----|-----------|---------|-------|-------------
`<td>Dummy1</td><td>Dummy2</td>` | `<td>` | `</td>` | `2` | `Dummy2`
`<td>Dummy1</td><td>Dummy2</td><td>Dummy3</td>` | `<td>` | `</td>` | `2` | `Dummy2`

## SpanBetweenNthIncluding
Returns all characters between the nth occurence of the given start and end text and including the texts themselves.

### Example
span | startText | endText | count | Return value
-----|-----------|---------|-------|-------------
`<td>Dummy1</td><td>Dummy2</td>` | `<td>` | `</td>` | `2` | `<td>Dummy2</td>`
`<td>Dummy1</td><td>Dummy2</td><td>Dummy3</td>` | `<td>` | `</td>` | `2` | `<td>Dummy2</td>`

## SpanCount
Returns the count of the given text.
Expand Down
45 changes: 45 additions & 0 deletions ReadOnlySpanExtensions/ReadOnlySpanExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,34 @@ public static ReadOnlySpan<char> SpanBetweenOuterIncluding(this ReadOnlySpan<cha
var (startIndex, endIndex) = GetPositionsForBetween(span, startText, endText, startPos, stringComparison, true);
return startIndex != -1 ? span.Slice(startIndex, startText.Length + endIndex + endText.Length) : ReadOnlySpan<char>.Empty;
}

/// <summary>
/// Returns all characters between the last occurence of the given start and end text.
/// </summary>
/// <param name="span">Span to search through.</param>
/// <param name="startText">Start text to search for.</param>
/// <param name="endText">End text to search for.</param>
/// <param name="startPos">Optional starting position.</param>
/// <param name="stringComparison">Optional culture & case sensitivity rule.</param>
public static ReadOnlySpan<char> SpanBetweenLast(this ReadOnlySpan<char> span, ReadOnlySpan<char> startText, ReadOnlySpan<char> endText, int startPos = 0, StringComparison stringComparison = StringComparison.Ordinal)
{
var (startIndex, endIndex) = GetPositionsForBetweenLast(span, startText, endText, startPos, stringComparison);
return startIndex != -1 ? span.Slice(startIndex + startText.Length, endIndex) : ReadOnlySpan<char>.Empty;
}

/// <summary>
/// Returns all characters between the last occurence of the given start and end text and including the texts themselves.
/// </summary>
/// <param name="span">Span to search through.</param>
/// <param name="startText">Start text to search for.</param>
/// <param name="endText">End text to search for.</param>
/// <param name="startPos">Optional starting position.</param>
/// <param name="stringComparison">Optional culture & case sensitivity rule.</param>
public static ReadOnlySpan<char> SpanBetweenLastIncluding(this ReadOnlySpan<char> span, ReadOnlySpan<char> startText, ReadOnlySpan<char> endText, int startPos = 0, StringComparison stringComparison = StringComparison.Ordinal)
{
var (startIndex, endIndex) = GetPositionsForBetweenLast(span, startText, endText, startPos, stringComparison);
return startIndex != -1 ? span.Slice(startIndex, startText.Length + endIndex + endText.Length) : ReadOnlySpan<char>.Empty;
}

/// <summary>
/// Returns all characters between the nth occurence of the given start and end text.
Expand Down Expand Up @@ -385,6 +413,23 @@ private static (int startIndex, int endIndex) GetPositionsForBetween(ReadOnlySpa
return (startIndex, endIndex - startIndex - startText.Length);
}

private static (int startIndex, int endIndex) GetPositionsForBetweenLast(ReadOnlySpan<char> span, ReadOnlySpan<char> startText, ReadOnlySpan<char> endText, int startPos, StringComparison stringComparison)
{
if (startText.Length == 0) return (-1, -1);
var endIndex = ValidateAndGetIndex(span, endText, startPos, stringComparison, true);
if (endIndex == -1) return (-1, -1);
var startIndex = GetIndex(span, startText, startPos, stringComparison, true);
if (startIndex == -1) return (-1, -1);
//We could do this directly but as it is a bit less efficient and should be such a rare scenario, cover it only if needed.
if (startIndex > endIndex - startText.Length)
{
span = span[..endIndex];
startIndex = GetIndex(span, startText, startPos, stringComparison, true);
if (startIndex == -1) return (-1, -1);
}
return (startIndex, endIndex - startIndex - startText.Length);
}

private static ReadOnlySpanPair<char> GetSpanPairSurrounding(ReadOnlySpan<char> span, ReadOnlySpan<char> startText, ReadOnlySpan<char> endText, int startPos, StringComparison stringComparison, bool includingTexts = false, bool lastForEndText = false)
{
var (startIndex, endIndex) = GetPositionsForBetween(span, startText, endText, startPos, stringComparison, lastForEndText);
Expand Down
7 changes: 5 additions & 2 deletions ReadOnlySpanExtensions/ReadOnlySpanExtensions.csproj
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Version>1.4.0</Version>
<PackageReleaseNotes>v1.4.0
<Version>1.5.0</Version>
<PackageReleaseNotes>v1.5.0
- Added SpanBetweenLast.

v1.4.0
- Added SpanBetweenNth &amp; SpanPairSurrounding (for single text).

v1.3.1
Expand Down
52 changes: 52 additions & 0 deletions ReadOnlySpanExtensionsTests/ReadOnlySpanExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,58 @@ public void ShouldReturnSpanBetweenOuterIncludingWithStartingPos(string input, s
Assert.That(result.ToString(), Is.EqualTo(expected));
}

[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "<td>", "</td>", "Dummy3")]
[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "<th>", "</th>", "")]
[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "", "</td>", "")]
[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "<td>", "", "")]
[TestCase("[X]Dummy[X]", "[X]", "[X]", "Dummy")]
[TestCase("[X]Dummy[X]", "X", "X", "]Dummy[")]
[TestCase("[X][X]", "[X]", "[X]", "")]
[TestCase("[X][X]", "X", "[X]", "]")]
public void ShouldReturnSpanBetweenLast(string input, string startText, string endText, string expected)
{
var inputSpan = input.AsSpan();
var result = inputSpan.SpanBetweenLast(startText, endText);
Assert.That(result.ToString(), Is.EqualTo(expected));
}

[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "<td>", "</td>", 0, "Dummy3")]
[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "<td>", "</td>", 29, "Dummy3")]
[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "<td>", "</td>", 30, "")]
[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "<td>", "</td>", 45, "")]
public void ShouldReturnSpanBetweenLastWithStartingPos(string input, string startText, string endText, int startingPos, string expected)
{
var inputSpan = input.AsSpan();
var result = inputSpan.SpanBetweenLast(startText, endText, startingPos);
Assert.That(result.ToString(), Is.EqualTo(expected));
}

[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "<td>", "</td>", "<td>Dummy3</td>")]
[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "<th>", "</th>", "")]
[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "", "</td>", "")]
[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "<td>", "", "")]
[TestCase("[X]Dummy[X]", "[X]", "[X]", "[X]Dummy[X]")]
[TestCase("[X]Dummy[X]", "X", "X", "X]Dummy[X")]
[TestCase("[X][X]", "[X]", "[X]", "[X][X]")]
[TestCase("[X][X]", "X", "[X]", "X][X]")]
public void ShouldReturnSpanBetweenLastIncluding(string input, string startText, string endText, string expected)
{
var inputSpan = input.AsSpan();
var result = inputSpan.SpanBetweenLastIncluding(startText, endText);
Assert.That(result.ToString(), Is.EqualTo(expected));
}

[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "<td>", "</td>", 0, "<td>Dummy3</td>")]
[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "<td>", "</td>", 29, "<td>Dummy3</td>")]
[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "<td>", "</td>", 30, "")]
[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "<td>", "</td>", 45, "")]
public void ShouldReturnSpanBetweenLastIncludingWithStartingPos(string input, string startText, string endText, int startingPos, string expected)
{
var inputSpan = input.AsSpan();
var result = inputSpan.SpanBetweenLastIncluding(startText, endText, startingPos);
Assert.That(result.ToString(), Is.EqualTo(expected));
}

[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "<td>", "</td>", 1, "Dummy")]
[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "<td>", "</td>", 2, "Dummy2")]
[TestCase("<td>Dummy</td><td>Dummy2</td><td>Dummy3</td>", "<td>", "</td>", 3, "Dummy3")]
Expand Down

0 comments on commit 7774686

Please sign in to comment.