// --------------------------------------------------------------------------------------------------------------------
//
// 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
}
}