using System.Collections.Generic; using System.Globalization; using System.Security.Cryptography; using System.Text; using System.Text.Json; using System.Text.RegularExpressions; using JetBrains.Annotations; using Volo.Abp; namespace System; /// /// Extension methods for String class. /// public static class AbpStringExtensions { /// /// Adds a char to end of given string if it does not ends with the char. /// public static string EnsureEndsWith(this string str, char c, StringComparison comparisonType = StringComparison.Ordinal) { Check.NotNull(str, nameof(str)); if (str.EndsWith(c.ToString(), comparisonType)) { return str; } return str + c; } /// /// Adds a char to beginning of given string if it does not starts with the char. /// public static string EnsureStartsWith(this string str, char c, StringComparison comparisonType = StringComparison.Ordinal) { Check.NotNull(str, nameof(str)); if (str.StartsWith(c.ToString(), comparisonType)) { return str; } return c + str; } /// /// Indicates whether this string is null or an System.String.Empty string. /// [ContractAnnotation("str:null => true")] public static bool IsNullOrEmpty([System.Diagnostics.CodeAnalysis.NotNullWhen(false)]this string? str) { return string.IsNullOrEmpty(str); } /// /// indicates whether this string is null, empty, or consists only of white-space characters. /// [ContractAnnotation("str:null => true")] public static bool IsNullOrWhiteSpace([System.Diagnostics.CodeAnalysis.NotNullWhen(false)]this string? str) { return string.IsNullOrWhiteSpace(str); } /// /// Gets a substring of a string from beginning of the string. /// /// Thrown if is null /// Thrown if is bigger that string's length public static string Left(this string str, int len) { Check.NotNull(str, nameof(str)); if (str.Length < len) { throw new ArgumentException("len argument can not be bigger than given string's length!"); } return str.Substring(0, len); } /// /// Converts line endings in the string to . /// public static string NormalizeLineEndings(this string str) { return str.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", Environment.NewLine); } /// /// Gets index of nth occurrence of a char in a string. /// /// source string to be searched /// Char to search in /// Count of the occurrence public static int NthIndexOf(this string str, char c, int n) { Check.NotNull(str, nameof(str)); var count = 0; for (var i = 0; i < str.Length; i++) { if (str[i] != c) { continue; } if ((++count) == n) { return i; } } return -1; } /// /// Removes first occurrence of the given postfixes from end of the given string. /// /// The string. /// one or more postfix. /// Modified string or the same string if it has not any of given postfixes [ContractAnnotation("null <= str:null")] public static string RemovePostFix(this string str, params string[] postFixes) { return str.RemovePostFix(StringComparison.Ordinal, postFixes); } /// /// Removes first occurrence of the given postfixes from end of the given string. /// /// The string. /// String comparison type /// one or more postfix. /// Modified string or the same string if it has not any of given postfixes [ContractAnnotation("null <= str:null")] public static string RemovePostFix(this string str, StringComparison comparisonType, params string[] postFixes) { if (str.IsNullOrEmpty()) { return str; } if (postFixes.IsNullOrEmpty()) { return str; } foreach (var postFix in postFixes) { if (str.EndsWith(postFix, comparisonType)) { return str.Left(str.Length - postFix.Length); } } return str; } /// /// Removes first occurrence of the given prefixes from beginning of the given string. /// /// The string. /// one or more prefix. /// Modified string or the same string if it has not any of given prefixes [ContractAnnotation("null <= str:null")] public static string RemovePreFix(this string str, params string[] preFixes) { return str.RemovePreFix(StringComparison.Ordinal, preFixes); } /// /// Removes first occurrence of the given prefixes from beginning of the given string. /// /// The string. /// String comparison type /// one or more prefix. /// Modified string or the same string if it has not any of given prefixes [ContractAnnotation("null <= str:null")] public static string RemovePreFix(this string str, StringComparison comparisonType, params string[] preFixes) { if (str.IsNullOrEmpty()) { return str; } if (preFixes.IsNullOrEmpty()) { return str; } foreach (var preFix in preFixes) { if (str.StartsWith(preFix, comparisonType)) { return str.Right(str.Length - preFix.Length); } } return str; } public static string ReplaceFirst(this string str, string search, string replace, StringComparison comparisonType = StringComparison.Ordinal) { Check.NotNull(str, nameof(str)); var pos = str.IndexOf(search, comparisonType); if (pos < 0) { return str; } var searchLength = search.Length; var replaceLength = replace.Length; var newLength = str.Length - searchLength + replaceLength; Span buffer = newLength <= 1024 ? stackalloc char[newLength] : new char[newLength]; // Copy the part of the original string before the search term str.AsSpan(0, pos).CopyTo(buffer); // Copy the replacement text replace.AsSpan().CopyTo(buffer.Slice(pos)); // Copy the remainder of the original string str.AsSpan(pos + searchLength).CopyTo(buffer.Slice(pos + replaceLength)); return buffer.ToString(); } /// /// Gets a substring of a string from end of the string. /// /// Thrown if is null /// Thrown if is bigger that string's length public static string Right(this string str, int len) { Check.NotNull(str, nameof(str)); if (str.Length < len) { throw new ArgumentException("len argument can not be bigger than given string's length!"); } return str.Substring(str.Length - len, len); } /// /// Uses string.Split method to split given string by given separator. /// public static string[] Split(this string str, string separator) { return str.Split(new[] { separator }, StringSplitOptions.None); } /// /// Uses string.Split method to split given string by given separator. /// public static string[] Split(this string str, string separator, StringSplitOptions options) { return str.Split(new[] { separator }, options); } /// /// Uses string.Split method to split given string by . /// public static string[] SplitToLines(this string str) { return str.Split(Environment.NewLine); } /// /// Uses string.Split method to split given string by . /// public static string[] SplitToLines(this string str, StringSplitOptions options) { return str.Split(Environment.NewLine, options); } /// /// Converts PascalCase string to camelCase string. /// /// String to convert /// set true to use current culture. Otherwise, invariant culture will be used. /// set true to if you want to convert 'XYZ' to 'xyz'. /// camelCase of the string [ContractAnnotation("null <= str:null")] public static string ToCamelCase(this string str, bool useCurrentCulture = false, bool handleAbbreviations = false) { if (string.IsNullOrWhiteSpace(str)) { return str; } if (str.Length == 1) { return useCurrentCulture ? str.ToLower() : str.ToLowerInvariant(); } if (handleAbbreviations && IsAllUpperCase(str)) { return useCurrentCulture ? str.ToLower() : str.ToLowerInvariant(); } return (useCurrentCulture ? char.ToLower(str[0]) : char.ToLowerInvariant(str[0])) + str.Substring(1); } /// /// Converts given PascalCase/camelCase string to sentence (by splitting words by space). /// Example: "ThisIsSampleSentence" is converted to "This is a sample sentence". /// /// String to convert. /// set true to use current culture. Otherwise, invariant culture will be used. [ContractAnnotation("null <= str:null")] public static string ToSentenceCase(this string str, bool useCurrentCulture = false) { if (string.IsNullOrWhiteSpace(str)) { return str; } return useCurrentCulture ? Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1])) : Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLowerInvariant(m.Value[1])); } /// /// Converts given PascalCase/camelCase string to kebab-case. /// /// String to convert. /// set true to use current culture. Otherwise, invariant culture will be used. [ContractAnnotation("null <= str:null")] public static string ToKebabCase(this string str, bool useCurrentCulture = false) { if (string.IsNullOrWhiteSpace(str)) { return str; } str = str.ToCamelCase(); return useCurrentCulture ? Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + "-" + char.ToLower(m.Value[1])) : Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + "-" + char.ToLowerInvariant(m.Value[1])); } /// /// Converts given PascalCase/camelCase string to snake case. /// Example: "ThisIsSampleSentence" is converted to "this_is_a_sample_sentence". /// https://github.com/npgsql/npgsql/blob/dev/src/Npgsql/NameTranslation/NpgsqlSnakeCaseNameTranslator.cs#L51 /// /// String to convert. /// public static string ToSnakeCase(this string str) { return str.IsNullOrWhiteSpace() ? str : JsonNamingPolicy.SnakeCaseLower.ConvertName(str); } /// /// Converts string to enum value. /// /// Type of enum /// String value to convert /// Returns enum object public static T ToEnum(this string value) where T : struct { Check.NotNull(value, nameof(value)); return (T)Enum.Parse(typeof(T), value); } /// /// Converts string to enum value. /// /// Type of enum /// String value to convert /// Ignore case /// Returns enum object public static T ToEnum(this string value, bool ignoreCase) where T : struct { Check.NotNull(value, nameof(value)); return (T)Enum.Parse(typeof(T), value, ignoreCase); } public static string ToMd5(this string str) { using (var md5 = MD5.Create()) { var inputBytes = Encoding.UTF8.GetBytes(str); var hashBytes = md5.ComputeHash(inputBytes); var sb = new StringBuilder(); foreach (var hashByte in hashBytes) { sb.Append(hashByte.ToString("X2")); } return sb.ToString(); } } /// /// Converts camelCase string to PascalCase string. /// /// String to convert /// set true to use current culture. Otherwise, invariant culture will be used. /// PascalCase of the string [ContractAnnotation("null <= str:null")] public static string ToPascalCase(this string str, bool useCurrentCulture = false) { if (string.IsNullOrWhiteSpace(str)) { return str; } if (str.Length == 1) { return useCurrentCulture ? str.ToUpper() : str.ToUpperInvariant(); } return (useCurrentCulture ? char.ToUpper(str[0]) : char.ToUpperInvariant(str[0])) + str.Substring(1); } /// /// Gets a substring of a string from beginning of the string if it exceeds maximum length. /// [ContractAnnotation("null <= str:null")] public static string? Truncate(this string? str, int maxLength) { if (str == null) { return null; } if (str.Length <= maxLength) { return str; } return str.Left(maxLength); } /// /// Gets a substring of a string from Ending of the string if it exceeds maximum length. /// [ContractAnnotation("null <= str:null")] public static string? TruncateFromBeginning(this string? str, int maxLength) { if (str == null) { return null; } if (str.Length <= maxLength) { return str; } return str.Right(maxLength); } /// /// Gets a substring of a string from beginning of the string if it exceeds maximum length. /// It adds a "..." postfix to end of the string if it's truncated. /// Returning string can not be longer than maxLength. /// /// Thrown if is null public static string? TruncateWithPostfix(this string? str, int maxLength) { return TruncateWithPostfix(str, maxLength, "..."); } /// /// Gets a substring of a string from beginning of the string if it exceeds maximum length. /// It adds given to end of the string if it's truncated. /// Returning string can not be longer than maxLength. /// /// Thrown if is null [ContractAnnotation("null <= str:null")] public static string? TruncateWithPostfix(this string? str, int maxLength, string postfix) { if (str == null) { return null; } if (str == string.Empty || maxLength == 0) { return string.Empty; } if (str.Length <= maxLength) { return str; } if (maxLength <= postfix.Length) { return postfix.Left(maxLength); } return str.Left(maxLength - postfix.Length) + postfix; } /// /// Converts given string to a byte array using encoding. /// public static byte[] GetBytes(this string str) { return str.GetBytes(Encoding.UTF8); } /// /// Converts given string to a byte array using the given /// public static byte[] GetBytes([NotNull] this string str, [NotNull] Encoding encoding) { Check.NotNull(str, nameof(str)); Check.NotNull(encoding, nameof(encoding)); return encoding.GetBytes(str); } private static bool IsAllUpperCase(string input) { for (int i = 0; i < input.Length; i++) { if (Char.IsLetter(input[i]) && !Char.IsUpper(input[i])) { return false; } } return true; } }