Skip to content

Commit 63f69a6

Browse files
Expansion and cleanup.
1 parent c97ca19 commit 63f69a6

21 files changed

Lines changed: 212 additions & 133 deletions

Source/Extensions.Equals.cs

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -111,43 +111,11 @@ public static bool SequenceEqual(this StringSegment source, ReadOnlySpan<char> o
111111

112112
/// <inheritdoc cref="TrimmedEquals(string?, ReadOnlySpan{char}, char, StringComparison)"/>
113113
public static bool TrimmedEquals(this string? source, ReadOnlySpan<char> other, StringComparison comparisonType = StringComparison.Ordinal)
114-
=> source is not null
115-
&& source.Length >= other.Length
116-
&& source.AsSpan().Trim().Equals(other, comparisonType);
114+
=> source?.AsSpan().Trim().Equals(other, comparisonType) == true;
117115

118116
/// <inheritdoc cref="TrimmedEquals(string?, StringSegment, char, StringComparison)"/>
119117
public static bool TrimmedEquals(this string? source, StringSegment other, StringComparison comparisonType = StringComparison.Ordinal)
120-
{
121-
if (source is null) return !other.HasValue;
122-
if (!other.HasValue) return false;
123-
int slen = source.Length, olen = other.Length;
124-
if (slen < olen) return false;
125-
var span = source.Trim();
126-
slen = span.Length;
127-
return slen == olen && slen switch
128-
{
129-
0 => true,
130-
1 when comparisonType == StringComparison.Ordinal => span[0] == other[0],
131-
_ => span.Equals(other, comparisonType),
132-
};
133-
}
134-
135-
/// <inheritdoc cref="TrimmedEquals(string?, StringSegment, char, StringComparison)"/>
136-
public static bool TrimmedEquals(this string? source, string? other, StringComparison comparisonType = StringComparison.Ordinal)
137-
{
138-
if (source is null) return other is null;
139-
if (other is null) return false;
140-
int slen = source.Length, olen = other.Length;
141-
if (slen < olen) return false;
142-
var span = source.AsSpan().Trim();
143-
slen = span.Length;
144-
return slen == olen && slen switch
145-
{
146-
0 => true,
147-
1 when comparisonType == StringComparison.Ordinal => span[0] == other[0],
148-
_ => span.Equals(other.AsSpan(), comparisonType),
149-
};
150-
}
118+
=> source is null ? !other.HasValue : other.HasValue && source.AsSpan().Trim().Equals(other, comparisonType);
151119

152120
/// <inheritdoc cref="TrimmedEquals(string?, StringSegment, char, StringComparison)"/>
153121
public static bool TrimmedEquals(this StringSegment source, StringSegment other, StringComparison comparisonType = StringComparison.Ordinal)

Source/Extensions.IndexOf.cs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,6 @@ public static int IndexOf(
155155
=> source.IndexOf(sequence, comparisonType);
156156
#endif
157157

158-
159158
#if NET6_0_OR_GREATER
160159
#else
161160
/// <summary>
@@ -218,7 +217,6 @@ public static int LastIndexOf(
218217
}
219218
#endif
220219

221-
222220
#pragma warning disable CS1587 // XML comment is not placed on a valid language element
223221
/// <summary>
224222
/// Reports the zero-based index of the first occurrence
@@ -233,8 +231,16 @@ public static int LastIndexOf(
233231
/// <inheritdoc cref="LastIndexOf(ReadOnlySpan{char}, ReadOnlySpan{char}, StringComparison)"/>
234232
#endif
235233
public static int LastIndexOf(this StringSegment source, ReadOnlySpan<char> sequence, StringComparison comparisonType)
236-
#pragma warning restore CS1587 // XML comment is not placed on a valid language element
237234
=> source.AsSpan().LastIndexOf(sequence, comparisonType);
235+
#pragma warning restore CS1587 // XML comment is not placed on a valid language element
236+
237+
/// <inheritdoc cref="LastIndexOf(StringSegment, ReadOnlySpan{char}, StringComparison)"/>
238+
public static int LastIndexOf(this ReadOnlySpan<char> source, StringSegment sequence, StringComparison comparisonType)
239+
=> source.LastIndexOf(sequence.AsSpan(), comparisonType);
240+
241+
/// <inheritdoc cref="LastIndexOf(StringSegment, ReadOnlySpan{char}, StringComparison)"/>
242+
public static int LastIndexOf(this StringSegment source, StringSegment sequence, StringComparison comparisonType)
243+
=> source.AsSpan().LastIndexOf(sequence.AsSpan(), comparisonType);
238244

239245
/// <summary>
240246
/// Reports the zero-based index of the first occurrence
@@ -263,6 +269,14 @@ public static int IndexOf(
263269
return index == -1 ? -1 : index + startIndex;
264270
}
265271

272+
/// <inheritdoc cref="IndexOf(ReadOnlySpan{char}, ReadOnlySpan{char}, int, StringComparison)"/>
273+
public static int IndexOf(
274+
this ReadOnlySpan<char> source,
275+
StringSegment sequence,
276+
int startIndex = 0,
277+
StringComparison comparisonType = StringComparison.Ordinal)
278+
=> source.IndexOf(sequence.AsSpan(), startIndex, comparisonType);
279+
266280
/// <inheritdoc cref="IndexOf(ReadOnlySpan{char}, ReadOnlySpan{char}, int, StringComparison)"/>
267281
public static int IndexOf(
268282
this StringSegment source,
@@ -271,6 +285,14 @@ public static int IndexOf(
271285
StringComparison comparisonType = StringComparison.Ordinal)
272286
=> source.AsSpan().IndexOf(sequence, startIndex, comparisonType);
273287

288+
/// <inheritdoc cref="IndexOf(ReadOnlySpan{char}, ReadOnlySpan{char}, int, StringComparison)"/>
289+
public static int IndexOf(
290+
this string source,
291+
ReadOnlySpan<char> sequence,
292+
int startIndex = 0,
293+
StringComparison comparisonType = StringComparison.Ordinal)
294+
=> source.AsSpan().IndexOf(sequence, startIndex, comparisonType);
295+
274296
/// <inheritdoc cref="IndexOf(ReadOnlySpan{char}, ReadOnlySpan{char}, int, StringComparison)"/>
275297
public static int IndexOf(
276298
this StringSegment source,
@@ -290,13 +312,27 @@ public static int IndexOf(
290312
StringComparison comparisonType)
291313
=> IndexOf(source.AsSpan(), sequence.AsSpan(), comparisonType);
292314

315+
/// <inheritdoc cref="IndexOf(StringSegment, StringSegment, StringComparison)"/>
316+
public static int IndexOf(
317+
this string source,
318+
ReadOnlySpan<char> sequence,
319+
StringComparison comparisonType)
320+
=> IndexOf(source.AsSpan(), sequence, comparisonType);
321+
293322
/// <inheritdoc cref="IndexOf(StringSegment, StringSegment, StringComparison)"/>
294323
public static int IndexOf(
295324
this StringSegment source,
296325
ReadOnlySpan<char> sequence,
297326
StringComparison comparisonType)
298327
=> IndexOf(source.AsSpan(), sequence, comparisonType);
299328

329+
/// <inheritdoc cref="IndexOf(StringSegment, StringSegment, StringComparison)"/>
330+
public static int IndexOf(
331+
this ReadOnlySpan<char> source,
332+
StringSegment sequence,
333+
StringComparison comparisonType)
334+
=> IndexOf(source, sequence.AsSpan(), comparisonType);
335+
300336
/// <inheritdoc cref="IndexOf(StringSegment, StringSegment, StringComparison)"/>
301337
public static int IndexOf(
302338
this string source,

Source/Extensions.Split.cs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,13 @@ public static ReadOnlySpan<char> FirstSplit(this ReadOnlySpan<char> source,
157157
return FirstSplitSpan(source, i, splitSequence.Length, out nextIndex);
158158
}
159159

160+
/// <inheritdoc cref="FirstSplit(StringSegment, StringSegment, out int, int, StringComparison)"/>
161+
public static ReadOnlySpan<char> FirstSplit(this ReadOnlySpan<char> source,
162+
StringSegment splitSequence,
163+
out int nextIndex,
164+
StringComparison comparisonType = StringComparison.Ordinal)
165+
=> source.FirstSplit(splitSequence.AsSpan(), out nextIndex, comparisonType);
166+
160167
/// <summary>
161168
/// Enumerates a string by segments that are separated by the split character.
162169
/// </summary>
@@ -165,8 +172,8 @@ public static ReadOnlySpan<char> FirstSplit(this ReadOnlySpan<char> source,
165172
/// <param name="options">Can specify to omit empty entries.</param>
166173
/// <returns>An enumerable of the segments.</returns>
167174
public static IEnumerable<string> SplitToEnumerable(this string source,
168-
char splitCharacter,
169-
StringSplitOptions options = StringSplitOptions.None)
175+
char splitCharacter,
176+
StringSplitOptions options = StringSplitOptions.None)
170177
{
171178
if (source is null) throw new ArgumentNullException(nameof(source));
172179
Contract.EndContractBlock();
@@ -177,7 +184,7 @@ public static IEnumerable<string> SplitToEnumerable(this string source,
177184
? Enumerable.Repeat(string.Empty, 1)
178185
: SplitAsEnumerableCore(),
179186
StringSplitOptions.RemoveEmptyEntries => source.Length == 0
180-
? []
187+
? Enumerable.Empty<string>()
181188
: SplitAsEnumerableCoreOmitEmpty(),
182189
_ => throw new System.ComponentModel.InvalidEnumArgumentException(),
183190
};
@@ -232,7 +239,7 @@ public static IEnumerable<string> SplitToEnumerable(
232239
? Enumerable.Repeat(string.Empty, 1)
233240
: SplitAsEnumerableCore(source, splitSequence, comparisonType),
234241
StringSplitOptions.RemoveEmptyEntries => source.Length == 0
235-
? []
242+
? Enumerable.Empty<string>()
236243
: SplitAsEnumerableCoreOmitEmpty(source, splitSequence, comparisonType),
237244
_ => throw new System.ComponentModel.InvalidEnumArgumentException(),
238245
};
@@ -277,7 +284,7 @@ public static IEnumerable<ReadOnlyMemory<char>> SplitAsMemory(
277284
? Enumerable.Repeat(ReadOnlyMemory<char>.Empty, 1)
278285
: SplitAsMemoryCore(source, splitCharacter),
279286
StringSplitOptions.RemoveEmptyEntries => source.Length == 0
280-
? []
287+
? Enumerable.Empty<ReadOnlyMemory<char>>()
281288
: SplitAsMemoryOmitEmpty(source, splitCharacter),
282289
_ => throw new System.ComponentModel.InvalidEnumArgumentException(),
283290
};
@@ -325,7 +332,7 @@ public static IEnumerable<ReadOnlyMemory<char>> SplitAsMemory(this string source
325332
? Enumerable.Repeat(ReadOnlyMemory<char>.Empty, 1)
326333
: SplitAsMemoryCore(source, splitSequence, comparisonType),
327334
StringSplitOptions.RemoveEmptyEntries => source.Length == 0
328-
? []
335+
? Enumerable.Empty<ReadOnlyMemory<char>>()
329336
: SplitAsMemoryOmitEmpty(source, splitSequence, comparisonType),
330337
_ => throw new System.ComponentModel.InvalidEnumArgumentException(),
331338
};
@@ -356,7 +363,7 @@ static IEnumerable<ReadOnlyMemory<char>> SplitAsMemoryCore(string source, string
356363
}
357364
}
358365

359-
static readonly IReadOnlyList<string> SingleEmpty = Array.AsReadOnly(new[] { string.Empty });
366+
static readonly IReadOnlyList<string> SingleEmpty = new List<string> { string.Empty }.AsReadOnly();
360367

361368
/// <summary>
362369
/// Splits a sequence of characters into strings using the character provided.
@@ -375,7 +382,7 @@ public static IReadOnlyList<string> Split(this ReadOnlySpan<char> source,
375382
return SingleEmpty;
376383

377384
case StringSplitOptions.RemoveEmptyEntries when source.Length == 0:
378-
return [];
385+
return Array.Empty<string>();
379386

380387
case StringSplitOptions.RemoveEmptyEntries:
381388
{
@@ -423,7 +430,7 @@ public static IReadOnlyList<string> Split(this ReadOnlySpan<char> source,
423430
return SingleEmpty;
424431

425432
case StringSplitOptions.RemoveEmptyEntries when source.IsEmpty:
426-
return [];
433+
return Array.Empty<string>();
427434

428435
case StringSplitOptions.RemoveEmptyEntries:
429436
{
@@ -451,4 +458,11 @@ public static IReadOnlyList<string> Split(this ReadOnlySpan<char> source,
451458
}
452459
}
453460
}
461+
462+
/// <inheritdoc cref="Split(ReadOnlySpan{char}, ReadOnlySpan{char}, StringSplitOptions, StringComparison)"/>
463+
public static IReadOnlyList<string> Split(this ReadOnlySpan<char> source,
464+
StringSegment splitSequence,
465+
StringSplitOptions options = StringSplitOptions.None,
466+
StringComparison comparisonType = StringComparison.Ordinal)
467+
=> source.Split(splitSequence.AsSpan(), options, comparisonType);
454468
}

Source/Extensions.StringSegment.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public static IEnumerable<StringSegment> SplitAsSegments(
6969
? Enumerable.Repeat(StringSegment.Empty, 1)
7070
: SplitAsSegmentsCore(source, splitCharacter),
7171
StringSplitOptions.RemoveEmptyEntries => source.Length == 0
72-
? []
72+
? Enumerable.Empty<StringSegment>()
7373
: SplitAsSegmentsCoreOmitEmpty(source, splitCharacter),
7474
_ => throw new System.ComponentModel.InvalidEnumArgumentException(),
7575
};
@@ -152,7 +152,7 @@ public static IEnumerable<StringSegment> SplitAsSegments(
152152
? throw new ArgumentNullException(nameof(pattern))
153153
: source.Length == 0
154154
? options == StringSplitOptions.RemoveEmptyEntries
155-
? []
155+
? Enumerable.Empty<StringSegment>()
156156
: Enumerable.Repeat(StringSegment.Empty, 1)
157157
: SplitCore(source, pattern, options);
158158

@@ -207,7 +207,7 @@ public static IEnumerable<StringSegment> SplitAsSegments(
207207
? Enumerable.Repeat(StringSegment.Empty, 1)
208208
: SplitAsSegmentsCore(source, splitSequence, comparisonType),
209209
StringSplitOptions.RemoveEmptyEntries => source.Length == 0
210-
? []
210+
? Enumerable.Empty<StringSegment>()
211211
: SplitAsSegmentsCoreOmitEmpty(source, splitSequence, comparisonType),
212212
_ => throw new System.ComponentModel.InvalidEnumArgumentException(),
213213
};

Source/Extensions._.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ public static partial class TextExtensions
1313
/// <summary>
1414
/// Compiled pattern for finding alpha-numeric sequences.
1515
/// </summary>
16-
public static readonly Regex ValidAlphaNumericOnlyPattern = new(@"^\w+$", RegexOptions.Compiled);
16+
public static readonly Regex ValidAlphaNumericOnlyPattern
17+
= new(@"^\w+$", RegexOptions.Compiled);
1718

1819
/// <summary>
1920
/// Compiled pattern for finding alpha-numeric sequences and possible surrounding white-space.
2021
/// </summary>
21-
public static readonly Regex ValidAlphaNumericOnlyUntrimmedPattern = new(@"^\s*\w+\s*$", RegexOptions.Compiled);
22+
public static readonly Regex ValidAlphaNumericOnlyUntrimmedPattern
23+
= new(@"^\s*\w+\s*$", RegexOptions.Compiled);
2224

2325
/// <summary>
2426
/// Converts a string to title-case.
@@ -182,7 +184,7 @@ public static IEnumerable<StringSegment> AsSegments(this Regex pattern, string i
182184
: input is null
183185
? throw new ArgumentNullException(nameof(input))
184186
: input.Length == 0
185-
? []
187+
? Enumerable.Empty<StringSegment>()
186188
: AsSegmentsCore(pattern, input);
187189

188190
static IEnumerable<StringSegment> AsSegmentsCore(Regex pattern, string input)
@@ -326,6 +328,7 @@ public static string ReplaceWhiteSpace(this string source, string replace = " ")
326328
/// <summary>
327329
/// String constant for carriage return and then newline.
328330
/// </summary>
331+
[Obsolete("Use Environment.NewLine instead.")]
329332
public const string Newline = "\r\n";
330333

331334
/// <summary>
@@ -338,7 +341,7 @@ public static void WriteLineNoTabs(this TextWriter writer, string? s = null)
338341
Contract.EndContractBlock();
339342

340343
if (s is not null) writer.Write(s);
341-
writer.Write(Newline);
344+
writer.Write(Environment.NewLine);
342345
}
343346

344347
/// <summary>
@@ -371,7 +374,7 @@ public static int GetHashCodeFromChars(this ReadOnlySpan<char> chars, StringComp
371374
int length = chars.Length > maxChars ? maxChars : chars.Length;
372375

373376
int hash = 17;
374-
switch(comparisonType)
377+
switch (comparisonType)
375378
{
376379
case StringComparison.Ordinal:
377380
case StringComparison.CurrentCulture:

Source/Open.Text.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929
<PackageIcon>logo.png</PackageIcon>
3030
<GenerateDocumentationFile>True</GenerateDocumentationFile>
3131
<PackageReadmeFile>README.md</PackageReadmeFile>
32+
<NoWarn>IDE0301;IDE0079</NoWarn>
33+
</PropertyGroup>
34+
35+
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
36+
<NoWarn>$(NoWarn);nullable</NoWarn>
3237
</PropertyGroup>
3338

3439
<ItemGroup>

Source/StringSegmentSearch.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public readonly ref struct StringSegmentSearch
4040
/// <inheritdoc cref="RightToLeft" path="/summary"/>
4141
/// </param>
4242
internal StringSegmentSearch(
43-
StringSegment source,
43+
StringSegment source,
4444
ReadOnlySpan<char> search,
4545
StringComparison comparisonType,
4646
bool rightToLeft)
@@ -149,6 +149,22 @@ public static StringSegmentSearch Find(
149149
bool rightToLeft = false)
150150
=> new(source, search, comparisonType, rightToLeft);
151151

152+
/// <inheritdoc cref="Find(StringSegment, ReadOnlySpan{char}, StringComparison, bool)"/>
153+
public static StringSegmentSearch Find(
154+
this string source,
155+
StringSegment search,
156+
StringComparison comparisonType = StringComparison.Ordinal,
157+
bool rightToLeft = false)
158+
=> new(source, search, comparisonType, rightToLeft);
159+
160+
/// <inheritdoc cref="Find(StringSegment, ReadOnlySpan{char}, StringComparison, bool)"/>
161+
public static StringSegmentSearch Find(
162+
this StringSegment source,
163+
StringSegment search,
164+
StringComparison comparisonType = StringComparison.Ordinal,
165+
bool rightToLeft = false)
166+
=> new(source, search, comparisonType, rightToLeft);
167+
152168
/// <summary>
153169
/// Finds the next occurrence of the specified character sequence within the source segment.
154170
/// </summary>

Tests/ComparableTests.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
using System;
2-
using Xunit;
3-
4-
namespace Open.Text.Tests;
1+
namespace Open.Text.Tests;
52

3+
[ExcludeFromCodeCoverage]
64
public static class ComparableTests
75
{
86
[Theory]

0 commit comments

Comments
 (0)