Skip to content

Commit c97ca19

Browse files
Add new string extension methods and optimize usings
Introduced new extension methods for ReadOnlySpan<char>, StringSegment, and string to enhance string operations with various comparison options. Added global using directives for commonly used namespaces to simplify code. Removed redundant using directives and updated project version to 7.1.0.
1 parent 38c4c2d commit c97ca19

20 files changed

Lines changed: 508 additions & 404 deletions

Benchmarks/EnumParseTests.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using BenchmarkDotNet.Attributes;
22
using FastEnumUtility;
3-
using System.Security;
43

54
namespace Open.Text.Benchmarks;
65

Source/EnumValue.cs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,6 @@
1-
// Ignore Spelling: Deconstruct
2-
3-
using Microsoft.Extensions.Primitives;
4-
using System;
5-
using System.Collections.Concurrent;
6-
using System.Collections.Generic;
1+
using System.Collections.Concurrent;
72
using System.Diagnostics;
8-
using System.Diagnostics.CodeAnalysis;
9-
using System.Linq;
103
using System.Linq.Expressions;
11-
using System.Runtime.CompilerServices;
12-
using System.Threading;
134
using static System.Linq.Expressions.Expression;
145
//using static FastExpressionCompiler.LightExpression.Expression;
156
namespace Open.Text;

Source/Extensions.Equals.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
using Microsoft.Extensions.Primitives;
2-
using System;
3-
4-
namespace Open.Text;
1+
namespace Open.Text;
52

63
public static partial class TextExtensions
74
{

Source/Extensions.FirstLast.cs

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
namespace Open.Text;
2+
public static partial class TextExtensions
3+
{
4+
/// <summary>
5+
/// Finds the first instance of a string and returns a StringSegment for subsequent use.
6+
/// </summary>
7+
/// <param name="source">The source string to search.</param>
8+
/// <param name="search">The string pattern to look for.</param>
9+
/// <param name="comparisonType">The string comparison type to use. Default is Ordinal.</param>
10+
/// <returns>
11+
/// The segment representing the found string.
12+
/// If not found, the result will have a length of 0 and its <see cref="StringSegment.HasValue"/> property will be <see langword="false"/>.
13+
/// </returns>
14+
public static StringSegment First(this StringSegment source, StringSegment search, StringComparison comparisonType = StringComparison.Ordinal)
15+
{
16+
if (!source.HasValue) throw new ArgumentException(MustBeSegmentWithValue, nameof(source));
17+
Contract.EndContractBlock();
18+
19+
if (search.Length == 0)
20+
return default;
21+
22+
var i = source.IndexOf(search, comparisonType);
23+
return i == -1 ? default : source.Subsegment(i, search.Length);
24+
}
25+
26+
/// <inheritdoc cref="First(StringSegment, StringSegment, StringComparison)"/>
27+
public static StringSegment First(this StringSegment source, char search, StringComparison comparisonType = StringComparison.Ordinal)
28+
{
29+
if (!source.HasValue) throw new ArgumentException(MustBeSegmentWithValue, nameof(source));
30+
Contract.EndContractBlock();
31+
32+
var i = source.IndexOf(search, comparisonType);
33+
return i == -1 ? default : source.Subsegment(i, 1);
34+
}
35+
36+
/// <inheritdoc cref="First(StringSegment, StringSegment, StringComparison)"/>
37+
public static StringSegment First(this string source, char search, StringComparison comparisonType = StringComparison.Ordinal)
38+
{
39+
if (source is null) throw new ArgumentNullException(nameof(source));
40+
Contract.EndContractBlock();
41+
42+
var i = source.IndexOf(search, comparisonType);
43+
return i == -1 ? default : source.AsSegment(i, 1);
44+
}
45+
46+
/// <inheritdoc cref="First(StringSegment, StringSegment, StringComparison)"/>
47+
public static StringSegment First(this string source, StringSegment search, StringComparison comparisonType = StringComparison.Ordinal)
48+
{
49+
if (source is null) throw new ArgumentNullException(nameof(source));
50+
Contract.EndContractBlock();
51+
52+
return First(source.AsSegment(), search, comparisonType);
53+
}
54+
55+
/// <summary>
56+
/// Finds the first instance of a pattern and returns a StringSegment for subsequent use.
57+
/// </summary>
58+
/// <param name="source">The source string to search.</param>
59+
/// <param name="pattern">The pattern to look for.</param>
60+
/// <returns>
61+
/// The segment representing the found string.
62+
/// If not found, the StringSegment.HasValue property will be false.
63+
/// </returns>
64+
/// <remarks>If the pattern is right-to-left, then it will return the first segment from the right.</remarks>
65+
[ExcludeFromCodeCoverage] // Reason: would just test already tested code.
66+
public static StringSegment First(this string source, Regex pattern)
67+
{
68+
if (source is null) throw new ArgumentNullException(nameof(source));
69+
if (pattern is null) throw new ArgumentNullException(nameof(pattern));
70+
Contract.EndContractBlock();
71+
72+
var match = pattern.Match(source);
73+
return match.Success ? new(source, match.Index, match.Length) : default;
74+
}
75+
76+
/// <inheritdoc cref="First(string, StringSegment, StringComparison)" />
77+
public static StringSegment First(this StringSegment source, ReadOnlySpan<char> search, StringComparison comparisonType = StringComparison.Ordinal)
78+
{
79+
if (!source.HasValue) throw new ArgumentException(MustBeSegmentWithValue, nameof(source));
80+
Contract.EndContractBlock();
81+
82+
if (search.IsEmpty)
83+
return default;
84+
85+
var i = source.AsSpan().IndexOf(search, comparisonType);
86+
return i == -1 ? default : new(source.Buffer, source.Offset + i, search.Length);
87+
}
88+
89+
/// <summary>
90+
/// Finds the last instance of a string and returns a StringSegment for subsequent use.
91+
/// </summary>
92+
/// <inheritdoc cref="First(StringSegment, StringSegment, StringComparison)"/>
93+
public static StringSegment Last(this StringSegment source, StringSegment search, StringComparison comparisonType = StringComparison.Ordinal)
94+
{
95+
if (!source.HasValue) throw new ArgumentException(MustBeSegmentWithValue, nameof(source));
96+
Contract.EndContractBlock();
97+
98+
if (search.Length == 0)
99+
return default;
100+
101+
var i = source.AsSpan().LastIndexOf(search, comparisonType);
102+
return i == -1 ? default : source.Subsegment(i, search.Length);
103+
}
104+
105+
/// <inheritdoc cref="Last(StringSegment, StringSegment, StringComparison)" />
106+
public static StringSegment Last(this string source, StringSegment search, StringComparison comparisonType = StringComparison.Ordinal)
107+
=> Last(source.AsSegment(), search, comparisonType);
108+
109+
/// <summary>
110+
/// Finds the last instance of a pattern and returns a StringSegment for subsequent use.
111+
/// </summary>
112+
/// <remarks>If the pattern is right-to-left, then it will return the last segment from the right (first segment from the left).</remarks>
113+
/// <inheritdoc cref="First(string, Regex)"/>
114+
public static StringSegment Last(this string source, Regex pattern)
115+
{
116+
if (source is null) throw new ArgumentNullException(nameof(source));
117+
if (pattern is null) throw new ArgumentNullException(nameof(pattern));
118+
Contract.EndContractBlock();
119+
120+
var matches = pattern.Matches(source);
121+
if (matches.Count == 0) return default;
122+
var match = matches[matches.Count - 1];
123+
return new(source, match.Index, match.Length);
124+
}
125+
126+
/// <inheritdoc cref="Last(StringSegment, StringSegment, StringComparison)" />
127+
public static StringSegment Last(this StringSegment source, ReadOnlySpan<char> search, StringComparison comparisonType = StringComparison.Ordinal)
128+
{
129+
if (!source.HasValue) throw new ArgumentException(MustBeSegmentWithValue, nameof(source));
130+
Contract.EndContractBlock();
131+
if (search.IsEmpty)
132+
return default;
133+
134+
var i = source.AsSpan().LastIndexOf(search, comparisonType);
135+
return i == -1 ? default : new(source.Buffer, source.Offset + i, search.Length);
136+
}
137+
}

0 commit comments

Comments
 (0)