From 77746865cf31fb5dac2cb157fb7861543d3c25f0 Mon Sep 17 00:00:00 2001 From: Daniel Bonecke Date: Tue, 22 Aug 2023 19:24:54 +0200 Subject: [PATCH] Added SpanBetweenLast & bumped version. --- README.md | 20 ++++++- .../ReadOnlySpanExtensions.cs | 45 ++++++++++++++++ .../ReadOnlySpanExtensions.csproj | 7 ++- .../ReadOnlySpanExtensionsTests.cs | 52 +++++++++++++++++++ 4 files changed, 120 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6ffce52..9786549 100644 --- a/README.md +++ b/README.md @@ -133,13 +133,29 @@ span | startText | endText | Return value -----|-----------|---------|------------- `Dummy1Dummy2` | `` | `` | `Dummy1Dummy2` +## SpanBetweenLast +Returns all characters between the last occurence of the given start and end text. + +### Example +span | startText | endText | Return value +-----|-----------|---------|------------- +`Dummy1Dummy2` | `` | `` | `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 +-----|-----------|---------|------------- +`Dummy1Dummy2` | `` | `` | `Dummy2` + ## SpanBetweenNth Returns all characters between the nth occurence of the given start and end text. ### Example span | startText | endText | count | Return value -----|-----------|---------|-------|------------- -`Dummy1Dummy2` | `` | `` | `2` | `Dummy2` +`Dummy1Dummy2Dummy3` | `` | `` | `2` | `Dummy2` ## SpanBetweenNthIncluding Returns all characters between the nth occurence of the given start and end text and including the texts themselves. @@ -147,7 +163,7 @@ Returns all characters between the nth occurence of the given start and end text ### Example span | startText | endText | count | Return value -----|-----------|---------|-------|------------- -`Dummy1Dummy2` | `` | `` | `2` | `Dummy2` +`Dummy1Dummy2Dummy3` | `` | `` | `2` | `Dummy2` ## SpanCount Returns the count of the given text. diff --git a/ReadOnlySpanExtensions/ReadOnlySpanExtensions.cs b/ReadOnlySpanExtensions/ReadOnlySpanExtensions.cs index 1332376..64bb363 100644 --- a/ReadOnlySpanExtensions/ReadOnlySpanExtensions.cs +++ b/ReadOnlySpanExtensions/ReadOnlySpanExtensions.cs @@ -217,6 +217,34 @@ public static ReadOnlySpan SpanBetweenOuterIncluding(this ReadOnlySpan.Empty; } + + /// + /// Returns all characters between the last occurence of the given start and end text. + /// + /// Span to search through. + /// Start text to search for. + /// End text to search for. + /// Optional starting position. + /// Optional culture & case sensitivity rule. + public static ReadOnlySpan SpanBetweenLast(this ReadOnlySpan span, ReadOnlySpan startText, ReadOnlySpan 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.Empty; + } + + /// + /// Returns all characters between the last occurence of the given start and end text and including the texts themselves. + /// + /// Span to search through. + /// Start text to search for. + /// End text to search for. + /// Optional starting position. + /// Optional culture & case sensitivity rule. + public static ReadOnlySpan SpanBetweenLastIncluding(this ReadOnlySpan span, ReadOnlySpan startText, ReadOnlySpan 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.Empty; + } /// /// Returns all characters between the nth occurence of the given start and end text. @@ -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 span, ReadOnlySpan startText, ReadOnlySpan 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 GetSpanPairSurrounding(ReadOnlySpan span, ReadOnlySpan startText, ReadOnlySpan endText, int startPos, StringComparison stringComparison, bool includingTexts = false, bool lastForEndText = false) { var (startIndex, endIndex) = GetPositionsForBetween(span, startText, endText, startPos, stringComparison, lastForEndText); diff --git a/ReadOnlySpanExtensions/ReadOnlySpanExtensions.csproj b/ReadOnlySpanExtensions/ReadOnlySpanExtensions.csproj index 393d8b0..48382b6 100644 --- a/ReadOnlySpanExtensions/ReadOnlySpanExtensions.csproj +++ b/ReadOnlySpanExtensions/ReadOnlySpanExtensions.csproj @@ -1,8 +1,11 @@ - 1.4.0 - v1.4.0 + 1.5.0 + v1.5.0 +- Added SpanBetweenLast. + +v1.4.0 - Added SpanBetweenNth & SpanPairSurrounding (for single text). v1.3.1 diff --git a/ReadOnlySpanExtensionsTests/ReadOnlySpanExtensionsTests.cs b/ReadOnlySpanExtensionsTests/ReadOnlySpanExtensionsTests.cs index f2c394e..d308031 100644 --- a/ReadOnlySpanExtensionsTests/ReadOnlySpanExtensionsTests.cs +++ b/ReadOnlySpanExtensionsTests/ReadOnlySpanExtensionsTests.cs @@ -433,6 +433,58 @@ public void ShouldReturnSpanBetweenOuterIncludingWithStartingPos(string input, s Assert.That(result.ToString(), Is.EqualTo(expected)); } + [TestCase("DummyDummy2Dummy3", "", "", "Dummy3")] + [TestCase("DummyDummy2Dummy3", "", "", "")] + [TestCase("DummyDummy2Dummy3", "", "", "")] + [TestCase("DummyDummy2Dummy3", "", "", "")] + [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("DummyDummy2Dummy3", "", "", 0, "Dummy3")] + [TestCase("DummyDummy2Dummy3", "", "", 29, "Dummy3")] + [TestCase("DummyDummy2Dummy3", "", "", 30, "")] + [TestCase("DummyDummy2Dummy3", "", "", 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("DummyDummy2Dummy3", "", "", "Dummy3")] + [TestCase("DummyDummy2Dummy3", "", "", "")] + [TestCase("DummyDummy2Dummy3", "", "", "")] + [TestCase("DummyDummy2Dummy3", "", "", "")] + [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("DummyDummy2Dummy3", "", "", 0, "Dummy3")] + [TestCase("DummyDummy2Dummy3", "", "", 29, "Dummy3")] + [TestCase("DummyDummy2Dummy3", "", "", 30, "")] + [TestCase("DummyDummy2Dummy3", "", "", 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("DummyDummy2Dummy3", "", "", 1, "Dummy")] [TestCase("DummyDummy2Dummy3", "", "", 2, "Dummy2")] [TestCase("DummyDummy2Dummy3", "", "", 3, "Dummy3")]