// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) VRMADA, All rights reserved. // // -------------------------------------------------------------------------------------------------------------------- using System; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using Random = UnityEngine.Random; namespace UltimateXR.Extensions.System { /// /// extensions. /// public static class StringExt { #region Public Methods /// /// Gets the number of occurrences of a string in another string. /// /// The string where to perform the search /// The string to find /// Whether the search should be case sensitive /// Number of occurrences of in the source string public static int GetOccurrenceCount(this string self, string key, bool caseSensitive = true) { if (string.IsNullOrEmpty(self) || string.IsNullOrEmpty(key)) { return 0; } if (caseSensitive) { return (self.Length - self.Replace(key, string.Empty).Length) / key.Length; } return (self.Length - self.ToLower().Replace(key.ToLower(), string.Empty).Length) / key.Length; } /// /// Gets the SHA-256 hash value of a string. /// /// String to get the SHA-256 hash value of /// SHA-256 hash value of the string public static byte[] GetSha256(this string self) { using HashAlgorithm algorithm = SHA256.Create(); return algorithm.ComputeHash(Encoding.ASCII.GetBytes(self)); } /// /// Gets the MD5 hash value of a string. /// /// String to get the MD5 hash value of /// MD5 hash value of the string public static byte[] GetMd5(this string self) { using HashAlgorithm algorithm = MD5.Create(); return algorithm.ComputeHash(Encoding.ASCII.GetBytes(self)); } /// /// Gets the double SHA-256 hash value of a string. /// /// String to get the double SHA-256 hash value of /// Double SHA-256 hash value of the string public static string GetSha256x2(this string self) { byte[] sha256 = self.GetSha256(); return sha256.Aggregate(new StringBuilder(sha256.Length * 2), (sb, b) => sb.AppendFormat("{0:x2}", b)).ToString(); } /// /// Gets the double MD5 hash value of a string. /// /// String to get the double MD5 hash value of /// Double MD5 hash value of the string public static string GetMd5x2(this string self) { byte[] md5 = self.GetMd5(); return md5.Aggregate(new StringBuilder(md5.Length * 2), (sb, b) => sb.AppendFormat("{0:x2}", b)).ToString(); } /// /// Gets a Guid result of hashing the string using SHA-256 and keeping the first 16 bytes. /// /// String to get the Guid hash value of /// Guid hash value of the string public static Guid GetGuid(this string self) { // Take the first 16 bytes of the hash to create a Guid byte[] guidBytes = new byte[16]; Buffer.BlockCopy(GetSha256(self), 0, guidBytes, 0, guidBytes.Length); return new Guid(guidBytes); } /// /// Replaces the invalid characters in a path with a given character. /// /// The path to process /// The valid character to use as replacement /// The invalid characters to replace /// New string with the replacements /// The replacement character is part of the invalid characters public static string ReplaceInvalidPathChars(this string self, char fallbackChar = PathFallbackChar, params char[] invalidChars) { if (invalidChars.Length == 0) { return self.ReplaceInvalidDirPathChars(fallbackChar); } if (invalidChars.Contains(fallbackChar)) { throw new ArgumentOutOfRangeException(nameof(fallbackChar), fallbackChar, "Fallback should be a valid character"); } return string.Join(fallbackChar.ToString(), self.Split(invalidChars)); } /// /// Replaces the invalid characters in a directory path with a given character. /// /// The directory path to process /// The valid character to use as replacement /// New string with the replacements /// The replacement character is part of the invalid characters public static string ReplaceInvalidDirPathChars(this string self, char fallbackChar = PathFallbackChar) { return self.ReplaceInvalidPathChars(fallbackChar, Path.GetInvalidPathChars()); } /// /// Replaces the invalid characters in a file path with a given character. /// /// The file path to process /// The valid character to use as replacement /// New string with the replacements /// The replacement character is part of the invalid characters public static string ReplaceInvalidFilePathChars(this string self, char fallbackChar = PathFallbackChar) { return self.ReplaceInvalidPathChars(fallbackChar, Path.GetInvalidFileNameChars()); } /// /// Creates a random string. /// /// String length /// Include letters in the string? /// Include numbers in the string? /// Random string with given length or if no letters and number were specified public static string RandomString(int length, bool includeLetters, bool includeNumbers) { const string lettersOnly = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const string numbersOnly = "0123456789"; const string lettersAndNumbers = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; if (includeLetters && !includeNumbers) { return new string(Enumerable.Repeat(lettersOnly, length).Select(s => s[Random.Range(0, s.Length)]).ToArray()); } if (!includeLetters && includeNumbers) { return new string(Enumerable.Repeat(numbersOnly, length).Select(s => s[Random.Range(0, s.Length)]).ToArray()); } if (includeLetters && includeNumbers) { return new string(Enumerable.Repeat(lettersAndNumbers, length).Select(s => s[Random.Range(0, s.Length)]).ToArray()); } return string.Empty; } /// /// Splits a string using CamelCase. /// /// Input string /// Output string with added spaces public static string SplitCamelCase(this string self) { return Regex.Replace(self, "([A-Z])", " $1", RegexOptions.Compiled).Trim(); } /// /// Throws an exception if the string is null or only contains whitespaces. /// /// The string to check /// The parameter name, used as argument for the exceptions /// is /// Whitespace string is not allowed public static void ThrowIfNullOrWhitespace(this string self, string paramName) { if (self is null) { throw new ArgumentNullException(paramName); } if (string.IsNullOrWhiteSpace(self)) { throw new ArgumentOutOfRangeException(paramName, self, "Value cannot be whitespace"); } } /// /// Throws an exception if the string is null or empty. /// /// The string /// The parameter name, used as arguments for the exceptions /// is /// Empty string is not allowed public static void ThrowIfNullOrEmpty(this string self, string paramName) { if (self == null) { throw new ArgumentNullException(paramName); } if (string.IsNullOrEmpty(self)) { throw new ArgumentException("Empty string is not allowed", paramName); } } #endregion #region Private Types & Data private const char PathFallbackChar = '_'; #endregion } }