/// <summary> /// Returns a value indicating whether any of the specified characters occurs within this string. /// </summary> /// <param name="value">The current string.</param> /// <param name="characters">The characters to seek.</param> /// <param name="comparisonType">One of the enumeration values that specifies the rules for the character matching.</param> /// <returns> /// <see langword="true" /> if <i>any</i> of the specified characters occurs within the string; otherwise, /// <see langword="false" />. /// </returns> /// <exception cref="T:System.ArgumentNullException"> /// <paramref name="characters" /> is <see langword="null" />. /// </exception> /// <exception cref="T:System.ArgumentException"> /// <paramref name="comparisonType" /> is not a valid <see cref="CharacterComparison" /> value. /// </exception> public static bool ContainsAny(this string?value, CharacterComparison comparisonType, params char[] characters) { if (value is null) { return(false); } if (characters is null) { throw new ArgumentNullException(nameof(characters)); } var comparer = CharacterComparer.FromComparison(comparisonType); if (characters.Length == 0) { return(false); } foreach (var t in characters) { foreach (var c in value.AsSpan()) { if (comparer.Compare(c, t) == 0) { return(true); } } } return(false); }
/// <summary> /// Gets the beginning of a string value until the <i>first</i> occurrence of the given <paramref name="match"/> /// or the whole string when the <paramref name="match"/> is not present. /// </summary> /// <param name="value">The value that might contain the match.</param> /// <param name="match">The string to search for.</param> /// <param name="comparisonType">One of the enumeration values that specifies the rules for the character matching.</param> /// <returns>The sub-string from beginning till the found match or the whole string if the match is not present.</returns> /// <exception cref="T:System.ArgumentNullException"> /// <paramref name="value" /> is <see langword="null" />. /// </exception> /// <exception cref="T:System.ArgumentException"> /// <paramref name="comparisonType" /> is not a valid <see cref="T:System.StringComparison" /> value. /// </exception> public static string Until(this string?value, char match, CharacterComparison comparisonType) { if (value is null) { throw new ArgumentNullException(nameof(value)); } var characterComparer = CharacterComparer.FromComparison(comparisonType); var spannedValue = value.AsSpan(); // do not allocate only find a window of match inside value var matchIndex = -1; var iterationIndex = 0; foreach (var c in spannedValue) { if (characterComparer.Compare(c, match) == 0) { matchIndex = iterationIndex; break; } iterationIndex++; } if (matchIndex < 0) { return(value); } // do not substring to avoid re-iterating from 0 to match-index // just pointer slice the left side of the string and re-allocate // into new string return(spannedValue.Slice(0, matchIndex).ToString()); }
/// <summary> /// Returns a value indicating whether all of the specified characters occur within this string. /// </summary> /// <param name="value">The current string.</param> /// <param name="characters">The characters to seek.</param> /// <param name="comparisonType">One of the enumeration values that specifies the rules for the character matching.</param> /// <returns> /// <see langword="true" /> if <i>all</i> of the specified characters occur within the string; otherwise, /// <see langword="false" />. /// </returns> /// <exception cref="T:System.ArgumentNullException"> /// <paramref name="characters" /> is <see langword="null" />. /// </exception> /// <exception cref="T:System.ArgumentException"> /// <paramref name="comparisonType" /> is not a valid <see cref="CharacterComparison" /> value. /// </exception> public static bool ContainsAll(this string?value, CharacterComparison comparisonType, params char[] characters) { if (value is null) { return(false); } if (characters is null) { throw new ArgumentNullException(nameof(characters)); } var characterComparer = CharacterComparer.FromComparison(comparisonType); if (characters.Length == 0) { return(false); } // implementation that avoid allocation of extra strings or char arrays // but pay for that by double iterating over string length item at worst case var lookup = new bool[characters.Length]; for (var i = 0; i < characters.Length; i++) { foreach (var c in value.AsSpan()) { if (characterComparer.Compare(c, characters[i]) == 0) { lookup[i] = true; } } } for (var i = 0; i < characters.Length; i++) { if (!lookup[i]) { return(false); } } return(true); }