< Summary

Class:GDX.StringExtensions
Assembly:GDX
File(s):./Packages/com.dotbunny.gdx/GDX/StringExtensions.cs
Covered lines:268
Uncovered lines:0
Coverable lines:268
Total lines:748
Line coverage:100% (268 of 268)
Covered branches:0
Total branches:0
Covered methods:22
Total methods:22
Method coverage:100% (22 of 22)

Coverage History

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
StringExtensions()0%110100%
Concatenate(...)0%9.587062.5%
Decrypt(...)0%770100%
Encrypt(...)0%660100%
GetAfterFirst(...)0%220100%
GetAfterLast(...)0%220100%
GetBeforeFirst(...)0%220100%
GetBeforeLast(...)0%220100%
GetStableHashCode(...)0%440100%
GetStableLowerCaseHashCode(...)0%880100%
GetStableUpperCaseHashCode(...)0%880100%
HasLowerCase(...)0%5.075085.71%
HasUpperCase(...)0%5.075085.71%
IsBooleanValue(...)0%10.4610083.33%
IsBooleanPositiveValue(...)0%6.176083.33%
IsIntegerValue(...)0%12.3310071.43%
IsNumeric(...)0%12.9112081.48%
CountOccurence(...)0%440100%
PartialMatch(...)0%4.134080%
PartialMatch(...)0%4.134080%
SplitCamelCase(...)0%110100%
StripNonAscii(...)0%110100%

File(s)

./Packages/com.dotbunny.gdx/GDX/StringExtensions.cs

#LineLine coverage
 1// Copyright (c) 2020-2024 dotBunny Inc.
 2// dotBunny licenses this file to you under the BSL-1.0 license.
 3// See the LICENSE file in the project root for more information.
 4
 5using System;
 6using System.IO;
 7using System.Runtime.CompilerServices;
 8using System.Runtime.ConstrainedExecution;
 9using System.Security;
 10using System.Security.Cryptography;
 11using System.Text;
 12using System.Text.RegularExpressions;
 13using GDX.Collections.Generic;
 14
 15namespace GDX
 16{
 17    /// <summary>
 18    ///     <see cref="string" /> Based Extension Methods
 19    /// </summary>
 20    [VisualScriptingCompatible(2)]
 21    public static class StringExtensions
 22    {
 23        /// <summary>
 24        ///     The ASCII decimal value shift required to change the case of a letter.
 25        /// </summary>
 26        public const int AsciiCaseShift = 32;
 27
 28        /// <summary>
 29        ///     The ASCII decimal value for a.
 30        /// </summary>
 31        public const int AsciiLowerCaseStart = 97;
 32
 33        /// <summary>
 34        ///     The ASCII decimal value for lowercase z.
 35        /// </summary>
 36        public const int AsciiLowerCaseEnd = 122;
 37
 38        /// <summary>
 39        ///     The ASCII decimal value for the number sign -.
 40        /// </summary>
 41        public const int AsciiNumberSign = 45;
 42
 43        /// <summary>
 44        ///     The ASCII decimal value for the decimal (.).
 45        /// </summary>
 46        public const int AsciiNumberDecimal = 46;
 47
 48        /// <summary>
 49        ///     The ASCII decimal value for the , separator.
 50        /// </summary>
 51        public const int AsciiNumberSeparator = 47;
 52
 53        /// <summary>
 54        ///     The ASCII decimal value for 0.
 55        /// </summary>
 56        public const int AsciiNumberStart = 48;
 57
 58        /// <summary>
 59        ///     The ASCII decimal value for 9.
 60        /// </summary>
 61        public const int AsciiNumberEnd = 57;
 62
 63        /// <summary>
 64        ///     The ASCII decimal value for uppercase A.
 65        /// </summary>
 66        public const int AsciiUpperCaseStart = 65;
 67
 68        /// <summary>
 69        ///     The ASCII  decimal value for uppercase Z.
 70        /// </summary>
 71        public const int AsciiUpperCaseEnd = 90;
 72
 73        /// <summary>
 74        ///     The default encryption key used when none is provided to the encryption related extensions.
 75        /// </summary>
 76        /// <remarks>
 77        ///     You can change this at runtime during some sort of initialization pass to being something unique to your
 78        ///     but it is not absolutely necessary. This must be a multiple of 8 bytes.
 79        /// </remarks>
 280        public static byte[] EncryptionDefaultKey = Encoding.UTF8.GetBytes("Awesome!");
 81
 82        /// <summary>
 83        ///     The IV (Initialization Vector) provided to the <see cref="DESCryptoServiceProvider" />.
 84        /// </summary>
 85        /// <remarks>
 86        ///     You can change this at runtime during some sort of initialization pass to being something unique to your
 87        ///     but it is not absolutely necessary. This must be a multiple of 8 bytes.
 88        /// </remarks>
 289        public static byte[] EncryptionInitializationVector = Encoding.UTF8.GetBytes("dotBunny");
 90
 91        /// <summary>
 92        ///     Concatenate an array of strings into one unified string.
 93        /// </summary>
 94        /// <param name="pieces">An array of strings</param>
 95        /// <param name="delimiter">An optional string which to use between <paramref name="pieces" /> when combining.</
 96        /// <param name="trailingDelimiter">Should a trailing <paramref name="delimiter" /> be appended?</param>
 97        /// <returns>A concatenated <see cref="string" />.</returns>
 98        public static string Concatenate(this string[] pieces, string delimiter = null, bool trailingDelimiter = false)
 299        {
 2100            StringBuilder builder = new StringBuilder();
 101
 2102            int count = pieces.Length;
 2103            bool hasDelimiter = delimiter != null;
 2104            int tail = count - 1;
 105
 2106            if (trailingDelimiter)
 1107            {
 8108                for (int i = 0; i < count; i++)
 3109                {
 3110                    builder.Append(pieces[i]);
 3111                    if (hasDelimiter)
 3112                    {
 3113                        builder.Append(delimiter);
 3114                    }
 3115                }
 1116            }
 117            else
 1118            {
 8119                for (int i = 0; i < count; i++)
 3120                {
 3121                    builder.Append(pieces[i]);
 3122                    if (hasDelimiter && i != tail)
 2123                    {
 2124                        builder.Append(delimiter);
 2125                    }
 3126                }
 1127            }
 128
 2129            return builder.ToString();
 2130        }
 131
 132        /// <summary>
 133        ///     Decrypt an encrypted <see cref="string" /> created by <see cref="Encrypt" />.
 134        /// </summary>
 135        /// <remarks>This will have quite a few allocations.</remarks>
 136        /// <param name="encryptedString">The encrypted <see cref="string" />.</param>
 137        /// <param name="encryptionKey">The key used to encrypt the <see cref="string" />.</param>
 138        /// <returns>The decrypted <see cref="string" />.</returns>
 139        public static string Decrypt(this string encryptedString, byte[] encryptionKey = null)
 2140        {
 2141            DESCryptoServiceProvider desProvider = new DESCryptoServiceProvider
 142            {
 143                Mode = CipherMode.ECB,
 144                Padding = PaddingMode.PKCS7,
 145                Key = encryptionKey != null && encryptionKey.Length > 0 ? encryptionKey : EncryptionDefaultKey,
 146                IV = EncryptionInitializationVector
 147            };
 2148            using MemoryStream stream = new MemoryStream(Convert.FromBase64String(encryptedString));
 2149            using CryptoStream cs = new CryptoStream(stream, desProvider.CreateDecryptor(), CryptoStreamMode.Read);
 2150            using StreamReader sr = new StreamReader(cs, Encoding.UTF8);
 2151            return sr.ReadToEnd();
 2152        }
 153
 154        /// <summary>
 155        ///     Encrypt a <see cref="string" /> utilizing a <see cref="DESCryptoServiceProvider" />.
 156        /// </summary>
 157        /// <remarks>This will have quite a few allocations.</remarks>
 158        /// <param name="decryptedString">The original <see cref="string" />.</param>
 159        /// <param name="encryptionKey">
 160        ///     The key to be used when encrypting the <see cref="string" />.  This must be a
 161        ///     multiple of 8 bytes.
 162        /// </param>
 163        /// <returns>The encrypted <see cref="string" />.</returns>
 164        public static string Encrypt(this string decryptedString, byte[] encryptionKey = null)
 3165        {
 3166            DESCryptoServiceProvider desProvider = new DESCryptoServiceProvider
 167            {
 168                Mode = CipherMode.ECB,
 169                Padding = PaddingMode.PKCS7,
 170                Key = encryptionKey != null && encryptionKey.Length > 0 ? encryptionKey : EncryptionDefaultKey,
 171                IV = EncryptionInitializationVector
 172            };
 3173            using MemoryStream stream = new MemoryStream();
 3174            using CryptoStream cs = new CryptoStream(stream, desProvider.CreateEncryptor(), CryptoStreamMode.Write);
 3175            byte[] data = Encoding.Default.GetBytes(decryptedString);
 3176            cs.Write(data, 0, data.Length);
 3177            cs.FlushFinalBlock();
 3178            return Convert.ToBase64String(stream.ToArray());
 3179        }
 180
 181        /// <summary>
 182        ///     Get the <see cref="string" /> after the first identified <paramref name="splitString" /> in
 183        ///     <paramref name="targetString" />.
 184        /// </summary>
 185        /// <param name="targetString">The target <see cref="string" /> to look in.</param>
 186        /// <param name="splitString">The divider which the <paramref name="targetString" /> should be split on.</param>
 187        /// <param name="comparison">Specifies the culture, case, and sort rules to be used.</param>
 188        /// <returns>
 189        ///     The content following the <paramref name="splitString" />, or <c>null</c> if none is found.
 190        /// </returns>
 191        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 192        public static string GetAfterFirst(this string targetString, string splitString,
 193            StringComparison comparison = StringComparison.Ordinal)
 1194        {
 1195            int splitIndex = targetString.IndexOf(splitString, 0, comparison);
 1196            return splitIndex < 0 ? null : targetString.Substring(splitIndex + splitString.Length);
 1197        }
 198
 199        /// <summary>
 200        ///     Get the <see cref="string" /> after the last identified <paramref name="splitString" /> in
 201        ///     <paramref name="targetString" />.
 202        /// </summary>
 203        /// <param name="targetString">The target <see cref="string" /> to look in.</param>
 204        /// <param name="splitString">The divider which the <paramref name="targetString" /> should be split on.</param>
 205        /// <param name="comparison">Specifies the culture, case, and sort rules to be used.</param>
 206        /// <returns>
 207        ///     The content following the <paramref name="splitString" />, or <c>null</c> if none is found.
 208        /// </returns>
 209        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 210        public static string GetAfterLast(this string targetString, string splitString,
 211            StringComparison comparison = StringComparison.Ordinal)
 1212        {
 1213            int splitIndex = targetString.LastIndexOf(splitString, targetString.Length - 1, comparison);
 1214            return splitIndex < 0 ? null : targetString.Substring(splitIndex + splitString.Length);
 1215        }
 216
 217        /// <summary>
 218        ///     Get the <see cref="string" /> before the first identified <paramref name="splitString" /> in
 219        ///     <paramref name="targetString" />.
 220        /// </summary>
 221        /// <param name="targetString">The target <see cref="string" /> to look in.</param>
 222        /// <param name="splitString">The divider which the <paramref name="targetString" /> should be split on.</param>
 223        /// <param name="comparison">Specifies the culture, case, and sort rules to be used.</param>
 224        /// <returns>The content before the <paramref name="splitString" />, or <c>null</c> if none is found.</returns>
 225        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 226        public static string GetBeforeFirst(this string targetString, string splitString,
 227            StringComparison comparison = StringComparison.Ordinal)
 1228        {
 1229            int splitIndex = targetString.IndexOf(splitString, 0, comparison);
 1230            return splitIndex < 0 ? null : targetString.Substring(0, splitIndex);
 1231        }
 232
 233        /// <summary>
 234        ///     Get the <see cref="string" /> before the last identified <paramref name="splitString" /> in
 235        ///     <paramref name="targetString" />.
 236        /// </summary>
 237        /// <param name="targetString">The target <see cref="string" /> to look in.</param>
 238        /// <param name="splitString">The divider which the <paramref name="targetString" /> should be split on.</param>
 239        /// <param name="comparison">Specifies the culture, case, and sort rules to be used.</param>
 240        /// <returns>The content before the <paramref name="splitString" />, or <c>null</c> if none is found.</returns>
 241        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 242        public static string GetBeforeLast(this string targetString, string splitString,
 243            StringComparison comparison = StringComparison.Ordinal)
 1244        {
 1245            int splitIndex = targetString.LastIndexOf(splitString, targetString.Length - 1, comparison);
 1246            return splitIndex < 0 ? null : targetString.Substring(0, splitIndex);
 1247        }
 248
 249        /// <summary>
 250        ///     <para>
 251        ///         Get the stable hash code value of <paramref name="targetString" />.
 252        ///     </para>
 253        /// </summary>
 254        /// <remarks>
 255        ///     This loosely based on the Fowler–Noll–Vo (FNV) hash function. It's value will be identical
 256        ///     to the value produced natively by processing a <see cref="string" /> with
 257        ///     <see cref="string.GetHashCode()" />, but with no allocations and no virtual calls.
 258        /// </remarks>
 259        /// <param name="targetString">The target <see cref="string" />.</param>
 260        /// <returns>A <see cref="int" /> value.</returns>
 261        [SecuritySafeCritical]
 262        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
 263        public static unsafe int GetStableHashCode(this string targetString)
 793264        {
 793265            fixed (char* src = targetString)
 793266            {
 793267                int hash1 = 5381;
 793268                int hash2 = hash1;
 269                int c;
 793270                char* s = src;
 271
 272                // Get character
 3966273                while ((c = s[0]) != 0)
 3484274                {
 275                    // Add to Hash #1
 3484276                    hash1 = ((hash1 << 5) + hash1) ^ c;
 277
 278                    // Get our second character
 3484279                    c = s[1];
 280
 3484281                    if (c == 0)
 311282                    {
 311283                        break;
 284                    }
 285
 3173286                    hash2 = ((hash2 << 5) + hash2) ^ c;
 3173287                    s += 2;
 3173288                }
 289
 793290                return hash1 + hash2 * 1566083941;
 291            }
 793292        }
 293
 294        /// <summary>
 295        ///     <para>
 296        ///         Get the stable hash code value of <paramref name="targetString" /> (converted to an uppercase
 297        ///         <see cref="string" />).
 298        ///     </para>
 299        /// </summary>
 300        /// <remarks>
 301        ///     This loosely based on the Fowler–Noll–Vo (FNV) hash function. It's value will be identical
 302        ///     to the value produced natively by processing a <see cref="string" /> with
 303        ///     <see cref="string.ToLower()" />.<see cref="string.GetHashCode()" />, but with no
 304        ///     allocations.
 305        /// </remarks>
 306        /// <param name="targetString">The target <see cref="string" />.</param>
 307        /// <returns>A <see cref="int" /> value.</returns>
 308        [SecuritySafeCritical]
 309        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
 310        public static unsafe int GetStableLowerCaseHashCode(this string targetString)
 11311        {
 11312            fixed (char* src = targetString)
 11313            {
 11314                int hash1 = 5381;
 11315                int hash2 = hash1;
 316                int c;
 11317                char* s = src;
 318
 319                // Get character
 64320                while ((c = s[0]) != 0)
 61321                {
 322                    // Check character value and shift it if necessary (32)
 61323                    if (c >= AsciiUpperCaseStart && c <= AsciiUpperCaseEnd)
 20324                    {
 20325                        c ^= AsciiCaseShift;
 20326                    }
 327
 328                    // Add to Hash #1
 61329                    hash1 = ((hash1 << 5) + hash1) ^ c;
 330
 331                    // Get our second character
 61332                    c = s[1];
 333
 61334                    if (c == 0)
 8335                    {
 8336                        break;
 337                    }
 338
 339                    // Check character value and shift it if necessary (32)
 53340                    if (c >= AsciiUpperCaseStart && c <= AsciiUpperCaseEnd)
 13341                    {
 13342                        c ^= AsciiCaseShift;
 13343                    }
 344
 53345                    hash2 = ((hash2 << 5) + hash2) ^ c;
 53346                    s += 2;
 53347                }
 348
 11349                return hash1 + hash2 * 1566083941;
 350            }
 11351        }
 352
 353        /// <summary>
 354        ///     <para>
 355        ///         Get the stable hash code value of <paramref name="targetString" /> (converted to an uppercase
 356        ///         <see cref="string" />).
 357        ///     </para>
 358        /// </summary>
 359        /// <remarks>
 360        ///     This loosely based on the Fowler–Noll–Vo (FNV) hash function. It's value will be identical
 361        ///     to the value produced natively by processing a <see cref="string" /> with
 362        ///     <see cref="string.ToUpper()" />.<see cref="string.GetHashCode()" />, but with no
 363        ///     allocations.
 364        /// </remarks>
 365        /// <param name="targetString">The target <see cref="string" />.</param>
 366        /// <returns>A <see cref="int" /> value.</returns>
 367        [SecuritySafeCritical]
 368        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
 369        public static unsafe int GetStableUpperCaseHashCode(this string targetString)
 34370        {
 34371            fixed (char* src = targetString)
 34372            {
 34373                int hash1 = 5381;
 34374                int hash2 = hash1;
 375                int c;
 34376                char* s = src;
 377
 378                // Get character
 191379                while ((c = s[0]) != 0)
 162380                {
 381                    // Check character value and shift it if necessary (32)
 162382                    if (c >= AsciiLowerCaseStart && c <= AsciiLowerCaseEnd)
 83383                    {
 83384                        c ^= AsciiCaseShift;
 83385                    }
 386
 387                    // Add to Hash #1
 162388                    hash1 = ((hash1 << 5) + hash1) ^ c;
 389
 390                    // Get our second character
 162391                    c = s[1];
 392
 162393                    if (c == 0)
 5394                    {
 5395                        break;
 396                    }
 397
 398                    // Check character value and shift it if necessary (32)
 157399                    if (c >= AsciiLowerCaseStart && c <= AsciiLowerCaseEnd)
 132400                    {
 132401                        c ^= AsciiCaseShift;
 132402                    }
 403
 157404                    hash2 = ((hash2 << 5) + hash2) ^ c;
 157405                    s += 2;
 157406                }
 407
 34408                return hash1 + hash2 * 1566083941;
 409            }
 34410        }
 411
 412        /// <summary>
 413        ///     Determine if there are any lowercase letters in the provided <paramref name="targetString" />.
 414        /// </summary>
 415        /// <param name="targetString">The target <see cref="string" />.</param>
 416        /// <returns>true/false if lowercase letters were found.</returns>
 417        [SecuritySafeCritical]
 418        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
 419        public static unsafe bool HasLowerCase(this string targetString)
 2420        {
 2421            fixed (char* src = targetString)
 2422            {
 423                int c;
 2424                char* s = src;
 425
 426                // Get character
 24427                while ((c = s[0]) != 0)
 23428                {
 23429                    if (c >= AsciiLowerCaseStart && c <= AsciiLowerCaseEnd)
 1430                    {
 1431                        return true;
 432                    }
 433
 22434                    s += 1;
 22435                }
 1436            }
 437
 1438            return false;
 2439        }
 440
 441        /// <summary>
 442        ///     Determine if there are any uppercase letters in the provided <paramref name="targetString" />.
 443        /// </summary>
 444        /// <param name="targetString">The target <see cref="string" />.</param>
 445        /// <returns>true/false if uppercase letters were found.</returns>
 446        [SecuritySafeCritical]
 447        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
 448        public static unsafe bool HasUpperCase(this string targetString)
 2449        {
 2450            fixed (char* src = targetString)
 2451            {
 452                int c;
 2453                char* s = src;
 454
 455                // Get character
 23456                while ((c = s[0]) != 0)
 22457                {
 22458                    if (c >= AsciiUpperCaseStart && c <= AsciiUpperCaseEnd)
 1459                    {
 1460                        return true;
 461                    }
 462
 21463                    s += 1;
 21464                }
 1465            }
 466
 1467            return false;
 2468        }
 469
 470        /// <summary>
 471        ///     Determine if the <paramref name="targetString" /> represents a boolean value arrangement.
 472        /// </summary>
 473        /// <param name="targetString">The target <see cref="string" />.</param>
 474        /// <returns>true/false if the <paramref name="targetString" /> can be evaluated as a boolean value.</returns>
 475        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 476        public static bool IsBooleanValue(this string targetString)
 2477        {
 478            // Get an optimized hash value
 2479            int hash = targetString.GetStableLowerCaseHashCode();
 480
 481            // Check
 2482            switch (hash)
 483            {
 484                case -971704226: // true
 485                case -1685090051: // false
 486                case 372029325: // 1
 487                case 372029326: // 0
 488                case -1273338385: // yes
 489                case 1496915069: // no
 490                case -1231968287: // on
 491                case -870054309: // off
 1492                    return true;
 493            }
 494
 1495            return false;
 2496        }
 497
 498        /// <summary>
 499        ///     Determine if the <paramref name="targetString" /> represents a positive boolean value arrangement.
 500        /// </summary>
 501        /// <example>
 502        ///     Useful method when trying to parse data for branching.
 503        ///     <code>
 504        ///         if(data["set"].IsBooleanPositiveValue())
 505        ///         {
 506        ///             ShouldBlueBox();
 507        ///         }
 508        ///     </code>
 509        /// </example>
 510        /// <param name="targetString">The target <see cref="string" />.</param>
 511        /// <returns>true/false if the <paramref name="targetString" /> can be evaluated as a positive boolean value.</r
 512        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 513        public static bool IsBooleanPositiveValue(this string targetString)
 2514        {
 2515            int hash = targetString.GetStableLowerCaseHashCode();
 2516            switch (hash)
 517            {
 518                case -971704226: // true
 519                case 372029325: // 1
 520                case -1273338385: // yes
 521                case -1231968287: // on
 1522                    return true;
 523                default:
 1524                    return false;
 525            }
 2526        }
 527
 528        /// <summary>
 529        ///     Determine if the <paramref name="targetString" /> is an <see cref="int" /> value.
 530        /// </summary>
 531        /// <remarks>
 532        ///     This method is meant for when you do not actually need the value returned, merely an evaluation if
 533        ///     the provided <paramref name="targetString" /> is an <see cref="int" />. This does not qualify
 534        ///     <see cref="float" /> values positively.
 535        /// </remarks>
 536        /// <param name="targetString">The target <see cref="string" />.</param>
 537        /// <returns>true/false if it contains an <see cref="int" />.</returns>
 538        [SecuritySafeCritical]
 539        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
 540        public static unsafe bool IsIntegerValue(this string targetString)
 5541        {
 5542            fixed (char* src = targetString)
 5543            {
 5544                char* s = src;
 5545                int c = s[0];
 546
 547                // Nothing
 5548                if (c == 0)
 1549                {
 1550                    return false;
 551                }
 552
 553                // Check first character
 4554                if (c != AsciiNumberSign && (c < AsciiNumberStart || c > AsciiNumberEnd))
 1555                {
 1556                    return false;
 557                }
 558
 559                // Get character
 12560                while ((c = s[1]) != 0)
 10561                {
 10562                    if (c < AsciiNumberStart || c > AsciiNumberEnd)
 1563                    {
 1564                        return false;
 565                    }
 566
 9567                    s += 1;
 9568                }
 2569            }
 570
 2571            return true;
 5572        }
 573
 574        /// <summary>
 575        ///     Is the <paramref name="targetString" /> a numeric value.
 576        /// </summary>
 577        /// <remarks>
 578        ///     <para>
 579        ///         The following requirements must be met to be considered a valid number in this method:
 580        ///     </para>
 581        ///     <list type="bullet">
 582        ///         <item>
 583        ///             <description>
 584        ///                 The first character may be an indicator of its sign, an explicit acceptance of <c>-</c> is m
 585        ///                 prefixed with <c>+</c>, the number will be found invalid.
 586        ///             </description>
 587        ///         </item>
 588        ///         <item>
 589        ///             <description>A single decimal point <c>.</c> may be present in the <paramref name="targetString"
 590        ///         </item>
 591        ///         <item>
 592        ///             <description>No alphabet characters are present in the <paramref name="targetString" />.</descri
 593        ///         </item>
 594        ///     </list>
 595        /// </remarks>
 596        /// <param name="targetString">The target <see cref="string" />.</param>
 597        /// <returns>true/false if the <paramref name="targetString" /> qualifies as a numeric value.</returns>
 598        [SecuritySafeCritical]
 599        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
 600        public static unsafe bool IsNumeric(this string targetString)
 3177601        {
 3177602            fixed (char* src = targetString)
 3177603            {
 3177604                char* s = src;
 3177605                int c = s[0];
 3177606                bool hasDecimal = false;
 607
 608                // Nothing
 3177609                if (c == 0)
 1610                {
 1611                    return false;
 612                }
 613
 614                // Check first character
 3176615                if (c != AsciiNumberSign && (c < AsciiNumberStart || c > AsciiNumberEnd))
 2345616                {
 2345617                    return false;
 618                }
 619
 620                // Get character
 1672621                while ((c = s[1]) != 0)
 842622                {
 842623                    if (c < AsciiNumberStart || c > AsciiNumberEnd)
 3624                    {
 3625                        if (c == AsciiNumberDecimal && !hasDecimal)
 2626                        {
 2627                            hasDecimal = true;
 2628                            s += 1;
 2629                            continue;
 630                        }
 631
 1632                        return false;
 633                    }
 634
 839635                    s += 1;
 839636                }
 830637            }
 638
 830639            return true;
 3177640        }
 641
 642        /// <summary>
 643        ///     Counts the number of times the needle (<paramref name="targetCharacter" />) appears in the haystack (
 644        ///     <paramref name="targetString" />).
 645        /// </summary>
 646        /// <remarks>Specifically created to avoid using LINQ and avoid an allocation.</remarks>
 647        /// <param name="targetString">The haystack.</param>
 648        /// <param name="targetCharacter">The needle.</param>
 649        /// <returns>The number of times <paramref name="targetCharacter" /> is found in <paramref name="targetString" /
 650        [SecuritySafeCritical]
 651        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
 652        public static unsafe int CountOccurence(this string targetString, char targetCharacter)
 2653        {
 2654            int counter = 0;
 2655            fixed (char* src = targetString)
 2656            {
 657                int c;
 2658                char* s = src;
 54659                while ((c = s[0]) != 0)
 52660                {
 52661                    if (c == targetCharacter)
 2662                    {
 2663                        counter++;
 2664                    }
 665
 52666                    s += 1;
 52667                }
 2668            }
 669
 2670            return counter;
 2671        }
 672
 673        /// <summary>
 674        ///     Does the <paramref name="haystack" /> partially contain the <paramref name="needle" />?
 675        /// </summary>
 676        /// <param name="haystack">An array of <see cref="string" />s.</param>
 677        /// <param name="needle">The <see cref="string" /> that is being looked for.</param>
 678        /// <returns>true/false if found.</returns>
 679        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 680        public static bool PartialMatch(this string[] haystack, string needle)
 3681        {
 3682            if (haystack == null)
 1683            {
 1684                return false;
 685            }
 686
 2687            int count = haystack.Length;
 14688            for (int i = 0; i < count; i++)
 6689            {
 6690                if (haystack[i].Contains(needle))
 1691                {
 1692                    return true;
 693                }
 5694            }
 695
 1696            return false;
 3697        }
 698
 699        /// <summary>
 700        ///     Does the <paramref name="haystack" /> partially contain the <paramref name="needle" />?
 701        /// </summary>
 702        /// <param name="haystack">A <see cref="SimpleList{T}" /> of <see cref="string" />s.</param>
 703        /// <param name="needle">The <see cref="string" /> that is being looked for.</param>
 704        /// <returns>true/false if found.</returns>
 705        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 706        public static bool PartialMatch(this SimpleList<string> haystack, string needle)
 3707        {
 3708            if (haystack.Count == 0)
 1709            {
 1710                return false;
 711            }
 712
 2713            int count = haystack.Count;
 14714            for (int i = 0; i < count; i++)
 6715            {
 6716                if (haystack.Array[i].Contains(needle))
 1717                {
 1718                    return true;
 719                }
 5720            }
 721
 1722            return false;
 3723        }
 724
 725        /// <summary>
 726        ///     Create a new string, splitting an existing string up based on camel case formatting.
 727        /// </summary>
 728        /// <param name="targetString">The target <see cref="string" />.</param>
 729        /// <param name="divider">The <see cref="string" /> to put in between the split <see cref="string" />.</param>
 730        /// <returns>A new <see cref="string" />.</returns>
 731        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 732        public static string SplitCamelCase(this string targetString, string divider = " ")
 2733        {
 2734            return Regex.Replace(targetString, "([A-Z])", $"{divider}$1", RegexOptions.None).Trim();
 2735        }
 736
 737        /// <summary>
 738        ///     Remove non ASCII characters from a <see cref="string" />.
 739        /// </summary>
 740        /// <param name="targetString">The <see cref="string" /> to be cleaned.</param>
 741        /// <returns>A <see cref="string" /> without ASCII characters.</returns>
 742        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 743        public static string StripNonAscii(this string targetString)
 36188744        {
 36188745            return Regex.Replace(targetString, @"[^\u0000-\u007F]+", string.Empty);
 36188746        }
 747    }
 748}

Coverage by test methods

















































































































Methods/Properties

StringExtensions()
Concatenate(System.String[], System.String, System.Boolean)
Decrypt(System.String, System.Byte[])
Encrypt(System.String, System.Byte[])
GetAfterFirst(System.String, System.String, System.StringComparison)
GetAfterLast(System.String, System.String, System.StringComparison)
GetBeforeFirst(System.String, System.String, System.StringComparison)
GetBeforeLast(System.String, System.String, System.StringComparison)
GetStableHashCode(System.String)
GetStableLowerCaseHashCode(System.String)
GetStableUpperCaseHashCode(System.String)
HasLowerCase(System.String)
HasUpperCase(System.String)
IsBooleanValue(System.String)
IsBooleanPositiveValue(System.String)
IsIntegerValue(System.String)
IsNumeric(System.String)
CountOccurence(System.String, System.Char)
PartialMatch(System.String[], System.String)
PartialMatch(GDX.Collections.Generic.SimpleList[String], System.String)
SplitCamelCase(System.String, System.String)
StripNonAscii(System.String)