< Summary

Information
Class: ArturRios.Util.Text.CharacterChecks
Assembly: ArturRios.Util
File(s): /home/ci/agent/workspace/dotnet-util-docs_main/app/src/Text/CharacterChecks.cs
Line coverage
100%
Covered lines: 28
Uncovered lines: 0
Coverable lines: 28
Total lines: 140
Line coverage: 100%
Branch coverage
100%
Covered branches: 18
Total branches: 18
Branch coverage: 100%
Method coverage
100%
Covered methods: 13
Fully covered methods: 13
Total methods: 13
Method coverage: 100%
Full method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
HasNumber(...)100%11100%
HasLowerChar(...)100%11100%
HasUpperChar(...)100%11100%
HasSpecialChar(...)100%11100%
HasNumber(...)100%11100%
HasLowerChar(...)100%11100%
HasUpperChar(...)100%11100%
HasSpecialChar(...)100%11100%
Classify(...)100%1818100%
Classify(...)100%11100%
Missing(...)100%11100%
Missing(...)100%11100%

File(s)

/home/ci/agent/workspace/dotnet-util-docs_main/app/src/Text/CharacterChecks.cs

#LineLine coverage
 1using System.Buffers;
 2using ArturRios.Util.Collections;
 3
 4namespace ArturRios.Util.Text;
 5
 6/// <summary>
 7/// Allocation-free character class checks over strings and spans.
 8/// </summary>
 9/// <remarks>
 10/// These are vectorized equivalents of the corresponding patterns in
 11/// <see cref="RegularExpressions.RegexCollection"/> and agree with them on every input: both are ASCII
 12/// only. The one exception is
 13/// <see cref="RegularExpressions.RegexCollection.HasNumberLowerAndUpperCharPattern"/>, whose <c>\d</c> also
 14/// accepts non-ASCII decimal digits that <see cref="HasNumber(string)"/> and <see cref="Classify(string)"/>
 15/// ignore. They deliberately do not use <see cref="char.IsDigit(char)"/>, <see cref="char.IsLower(char)"/>
 16/// or <see cref="char.IsUpper(char)"/>, which are Unicode-aware and would report, for example, the
 17/// Arabic-Indic digit three as a digit and the German sharp s as a lowercase letter.
 18/// </remarks>
 19public static class CharacterChecks
 20{
 121    private static readonly SearchValues<char> Digits = SearchValues.Create(Characters.Digits);
 122    private static readonly SearchValues<char> LowerLetters = SearchValues.Create(Characters.LowerLetters);
 123    private static readonly SearchValues<char> UpperLetters = SearchValues.Create(Characters.UpperLetters);
 124    private static readonly SearchValues<char> SpecialChars = SearchValues.Create(Characters.Special);
 25
 26    /// <summary>Checks whether <paramref name="value"/> contains at least one ASCII digit.</summary>
 27    /// <param name="value">Input text.</param>
 28    /// <returns><see langword="true"/> when a digit 0-9 is present.</returns>
 1529    public static bool HasNumber(this ReadOnlySpan<char> value) => value.ContainsAny(Digits);
 30
 31    /// <summary>Checks whether <paramref name="value"/> contains at least one ASCII lowercase letter.</summary>
 32    /// <param name="value">Input text.</param>
 33    /// <returns><see langword="true"/> when a letter a-z is present.</returns>
 1234    public static bool HasLowerChar(this ReadOnlySpan<char> value) => value.ContainsAny(LowerLetters);
 35
 36    /// <summary>Checks whether <paramref name="value"/> contains at least one ASCII uppercase letter.</summary>
 37    /// <param name="value">Input text.</param>
 38    /// <returns><see langword="true"/> when a letter A-Z is present.</returns>
 1139    public static bool HasUpperChar(this ReadOnlySpan<char> value) => value.ContainsAny(UpperLetters);
 40
 41    /// <summary>Checks whether <paramref name="value"/> contains at least one <see cref="Characters.Special"/> characte
 42    /// <param name="value">Input text.</param>
 43    /// <returns><see langword="true"/> when a special character is present.</returns>
 744    public static bool HasSpecialChar(this ReadOnlySpan<char> value) => value.ContainsAny(SpecialChars);
 45
 46    /// <summary>Checks whether <paramref name="value"/> contains at least one ASCII digit.</summary>
 47    /// <param name="value">Input text. A <see langword="null"/> value contains nothing.</param>
 48    /// <returns><see langword="true"/> when a digit 0-9 is present.</returns>
 1449    public static bool HasNumber(this string? value) => value.AsSpan().HasNumber();
 50
 51    /// <summary>Checks whether <paramref name="value"/> contains at least one ASCII lowercase letter.</summary>
 52    /// <param name="value">Input text. A <see langword="null"/> value contains nothing.</param>
 53    /// <returns><see langword="true"/> when a letter a-z is present.</returns>
 1254    public static bool HasLowerChar(this string? value) => value.AsSpan().HasLowerChar();
 55
 56    /// <summary>Checks whether <paramref name="value"/> contains at least one ASCII uppercase letter.</summary>
 57    /// <param name="value">Input text. A <see langword="null"/> value contains nothing.</param>
 58    /// <returns><see langword="true"/> when a letter A-Z is present.</returns>
 1159    public static bool HasUpperChar(this string? value) => value.AsSpan().HasUpperChar();
 60
 61    /// <summary>Checks whether <paramref name="value"/> contains at least one <see cref="Characters.Special"/> characte
 62    /// <param name="value">Input text. A <see langword="null"/> value contains nothing.</param>
 63    /// <returns><see langword="true"/> when a special character is present.</returns>
 764    public static bool HasSpecialChar(this string? value) => value.AsSpan().HasSpecialChar();
 65
 66    /// <summary>
 67    /// Reports every <see cref="CharacterClasses"/> present in <paramref name="value"/> in a single pass.
 68    /// </summary>
 69    /// <param name="value">Input text.</param>
 70    /// <returns>The classes present, or <see cref="CharacterClasses.None"/> when none are.</returns>
 71    /// <remarks>
 72    /// Unlike <see cref="RegularExpressions.RegexCollection.HasNumberLowerAndUpperCharPattern"/>, which walks
 73    /// the input once per lookahead and rejects anything spanning more than one line, this reads the input
 74    /// once, stops as soon as every class has been seen, and is indifferent to newlines.
 75    /// </remarks>
 76    public static CharacterClasses Classify(this ReadOnlySpan<char> value)
 77    {
 78        const CharacterClasses everything = CharacterClasses.Digit | CharacterClasses.Lower |
 79                                            CharacterClasses.Upper | CharacterClasses.Special;
 11680        var found = CharacterClasses.None;
 81
 54682        foreach (var character in value)
 83        {
 15884            if (character is >= '0' and <= '9')
 85            {
 2786                found |= CharacterClasses.Digit;
 87            }
 13188            else if (character is >= 'a' and <= 'z')
 89            {
 4890                found |= CharacterClasses.Lower;
 91            }
 8392            else if (character is >= 'A' and <= 'Z')
 93            {
 4394                found |= CharacterClasses.Upper;
 95            }
 4096            else if (SpecialChars.Contains(character))
 97            {
 3598                found |= CharacterClasses.Special;
 99            }
 100
 158101            if (found == everything)
 102            {
 2103                return everything;
 104            }
 105        }
 106
 114107        return found;
 108    }
 109
 110    /// <summary>
 111    /// Reports every <see cref="CharacterClasses"/> present in <paramref name="value"/> in a single pass.
 112    /// </summary>
 113    /// <param name="value">Input text. A <see langword="null"/> value contains nothing.</param>
 114    /// <returns>The classes present, or <see cref="CharacterClasses.None"/> when none are.</returns>
 106115    public static CharacterClasses Classify(this string? value) => value.AsSpan().Classify();
 116
 117    /// <summary>
 118    /// Reports which of the <paramref name="required"/> classes <paramref name="value"/> does not contain.
 119    /// </summary>
 120    /// <param name="value">Input text.</param>
 121    /// <param name="required">The classes the caller demands.</param>
 122    /// <returns>
 123    /// The required classes that are absent, or <see cref="CharacterClasses.None"/> when every requirement
 124    /// is met. Classes present but not required are never reported.
 125    /// </returns>
 126    public static CharacterClasses Missing(this ReadOnlySpan<char> value, CharacterClasses required) =>
 9127        required & ~value.Classify();
 128
 129    /// <summary>
 130    /// Reports which of the <paramref name="required"/> classes <paramref name="value"/> does not contain.
 131    /// </summary>
 132    /// <param name="value">Input text. A <see langword="null"/> value is missing every requirement.</param>
 133    /// <param name="required">The classes the caller demands.</param>
 134    /// <returns>
 135    /// The required classes that are absent, or <see cref="CharacterClasses.None"/> when every requirement
 136    /// is met. Classes present but not required are never reported.
 137    /// </returns>
 138    public static CharacterClasses Missing(this string? value, CharacterClasses required) =>
 9139        value.AsSpan().Missing(required);
 140}