using System; using System.Text; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using System.Globalization; using System.Security.Cryptography; using System.ComponentModel.DataAnnotations; using System.Text.Json; namespace ExtensionMethods { public static class StringExtensions { /// /// SQL Like implementation /// /// /// /// public static bool Like(this string text, string wildcardedText) { text = text ?? ""; wildcardedText = wildcardedText ?? ""; return Regex.IsMatch(text, wildcardedText.WildcardToRegular(), RegexOptions.IgnoreCase | RegexOptions.Multiline); } /// /// Converts wildcarded string tgo regex /// /// /// private static string WildcardToRegular(this string value) => $"^{Regex.Escape(value).Replace("\\?", ".").Replace("\\*", ".*")}$"; /// /// VB.Net Left implementation /// /// /// /// public static string Left(this string s, int count) { return s.Substring(0, count); } /// /// VB.Net Right implementation /// /// /// /// public static string Right(this string s, int count) { return s.Substring(s.Length - count, count); } /// /// VB.Net Mid implementation /// /// /// /// /// public static string Mid(this string s, int index, int count) { return s.Substring(index, count); } /// /// VB.Net ToInteger implementation /// /// /// public static int ToInteger(this string s) { var integerValue = 0; int.TryParse(s, out integerValue); return integerValue; } /// /// VB.Net IsInteger implementations /// /// /// public static bool IsInteger(this string s) => new Regex("^-[0-9]+$|^[0-9]+$").Match(s).Success; public static StringBuilder Prepend(this StringBuilder sb, string content) => sb.Insert(0, content); public static T ToEnum(this string input) where T : struct { var result = default(T); if (string.IsNullOrWhiteSpace(input)) return result; bool parseSucceeded = Enum.TryParse(input, true, out result); if (parseSucceeded) return result; // se fallisce il parse per valore proviamo ad usare il DisplayAttribute.Name var enumType = typeof(T); foreach (T enumItem in Enum.GetValues(enumType)) { var att = enumType.GetMember(enumItem.ToString())[0] .GetCustomAttributes(typeof(DisplayAttribute), false).SingleOrDefault(); var displayName = ((DisplayAttribute)att).GetName(); if (input.Equals(displayName, StringComparison.InvariantCultureIgnoreCase)) return enumItem; } throw new NotSupportedException($"Cannot parse the value '{input}' for {enumType}"); } public static T? ToNullableEnum(this string input) where T : struct => !string.IsNullOrWhiteSpace(input) ? input.ToEnum() : default(T?); public static string ToNull(this string s) => !string.IsNullOrWhiteSpace(s) ? s : null; public static string NullIfEmptyString(this string s) => s.ToNull(); public static long ToLong(this string s) { if (!long.TryParse(s, NumberStyles.Any, NumberFormatInfo.InvariantInfo, out long result)) result = !string.IsNullOrWhiteSpace(s) ? s.ToUpper().GetHashCode() : default; return result; } public static long? ToNullableLong(this string s) => !string.IsNullOrWhiteSpace(s) ? s.ToLong() : default(long?); public static int ToInt(this string s) { if (!int.TryParse(s, NumberStyles.Any, NumberFormatInfo.InvariantInfo, out int result)) result = !string.IsNullOrWhiteSpace(s) ? s.ToUpper().GetHashCode() : default; return result; } public static int? ToNullableInt(this string s) => !string.IsNullOrWhiteSpace(s) ? s.ToInt() : default(int?); public static uint ToUint(this string s) { if (!uint.TryParse(s, NumberStyles.Any, NumberFormatInfo.InvariantInfo, out uint result)) result = !string.IsNullOrWhiteSpace(s) ? (uint)s.ToUpper().GetHashCode() : default; return result; } public static uint? ToNullableUint(this string s) => !string.IsNullOrWhiteSpace(s) ? s.ToUint() : default(uint?); public static decimal ToDecimal(this string s) { if (!int.TryParse(s, NumberStyles.Any, NumberFormatInfo.InvariantInfo, out int result)) result = !string.IsNullOrWhiteSpace(s) ? s.ToUpper().GetHashCode() : default; return result; } public static decimal? ToNullableDecimal(this string s) => !string.IsNullOrWhiteSpace(s) ? s.ToDecimal() : default(decimal?); public static double ToDouble(this string s) { if (!double.TryParse(s, NumberStyles.Any, NumberFormatInfo.InvariantInfo, out double result)) result = !string.IsNullOrWhiteSpace(s) ? s.ToUpper().GetHashCode() : default; return result; } public static double? ToNullableDouble(this string s) => !string.IsNullOrWhiteSpace(s) ? s.ToDouble() : default(double?); #region DateTime public static DateTime ToDate(this string s, string[] formats) { return DateTime.TryParseExact(s, formats, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime datetime) ? DateTime.SpecifyKind(datetime, DateTimeKind.Utc) : throw new ApplicationException($"the date [{s}] is not in required format: [{formats[0]}]"); } public static DateTime ToDate(this string s) => s.ToDate(new string[] { "dd/MM/yyyy" }); public static DateTime? ToNullableDate(this string s) => !string.IsNullOrEmpty(s) ? s.ToDate() : default(DateTime?); public static DateTime? ToNullableDate(this string s, string[] formats) => !string.IsNullOrEmpty(s) ? s.ToDate(formats) : default(DateTime?); public static DateTime ToDateTime(this string s, string[] formats) { if (s == "Now") return DateTime.Now; else if (s == "UtcNow") return DateTime.UtcNow; else if (s == "Today") return DateTime.Today; DateTime result; if (!DateTime.TryParseExact(s, formats, new DateTimeFormatInfo(), DateTimeStyles.None, out result)) throw new ApplicationException(string.Format("unable to parse exact date from value [{0}] with formats [{1}]", s, string.Join(", ", formats))); return DateTime.SpecifyKind(result, DateTimeKind.Utc); } public static DateTime ToDateTime(this string s) => s.ToDateTime(new string[] { "dd/MM/yyyy", "dd/MM/yyyy HH:mm:ss", "dd/MM/yyyy HH:mm", "yyyy-MM-dd'T'HH:mm:ss'Z'" }); public static DateTime? ToNullableDateTime(this string s) => !string.IsNullOrWhiteSpace(s) ? s.ToDateTime() : default(DateTime?); public static DateTime? ToNullableDateTime(this string s, string[] formats) => !string.IsNullOrWhiteSpace(s) ? s.ToDateTime(formats) : default(DateTime?); #endregion public static bool ToBool(this string s) => new string[] { "ok", "yes", "y", "true", "1" }.Any(x => string.Equals(x, s, StringComparison.InvariantCultureIgnoreCase)); public static bool? ToNullableBool(this string s) => !string.IsNullOrWhiteSpace(s) ? s.ToBool() : default(bool?); public static Guid ToGuid(this string text) { if (Guid.TryParse(text, out var value)) return value; using var md5 = MD5.Create(); byte[] hash = md5.ComputeHash(Encoding.Default.GetBytes(text.ToUpper())); return new Guid(hash); } public static Guid? ToNullableGuid(this string s) => !string.IsNullOrWhiteSpace(s) ? s.ToGuid() : default(Guid?); public static string[] StringSplit(this string s, char c) { return s.Split(c).Select(x => x.Trim()).ToArray(); } /// /// /// /// /// public static string ToTitle(this string s) { if (!string.IsNullOrWhiteSpace(s)) { var tmp = s.ToCharArray(); tmp[0] = char.ToUpper(tmp[0]); s = new string(tmp); } return s; } public static IEnumerable ExtractUrls(this string s) { var urls = new List(); foreach (Match match in Regex.Matches(s, @"(http|ftp|https):\/\/([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])")) { if (Uri.TryCreate(match.Value, UriKind.Absolute, out Uri uri)) { urls.Add(uri); } } return urls.Distinct(); } public static string Format(this string s, params object[] args) => string.Format(s, args); /// /// Adds elipsis /// /// /// /// public static string Excerpt(this string s, int length = 60) => string.IsNullOrEmpty(s) || s.Length < length ? s : s.Substring(0, length - 3) + "..."; /// /// Converts JSON string to object /// /// /// /// public static T? ToObject(this string s) => JsonSerializer.Deserialize(s, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); /// /// Adapted from .Net [EmailAddres] model validation attribute /// https://referencesource.microsoft.com/#System.ComponentModel.DataAnnotations/DataAnnotations/EmailAddressAttribute.cs,17f9a2457ddc8d93 /// /// /// public static bool IsValidEmail(this string? s) { Regex CreateRegEx() { const string pattern = @"^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$"; const RegexOptions options = RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture; // Set explicit regex match timeout, sufficient enough for email parsing // Unless the global REGEX_DEFAULT_MATCH_TIMEOUT is already set TimeSpan matchTimeout = TimeSpan.FromSeconds(2); try { if (AppDomain.CurrentDomain.GetData("REGEX_DEFAULT_MATCH_TIMEOUT") == null) { return new Regex(pattern, options, matchTimeout); } } catch { // Fallback on error } // Legacy fallback (without explicit match timeout) return new Regex(pattern, options); } // This attribute provides server-side email validation equivalent to jquery validate, // and therefore shares the same regular expression. See unit tests for examples. var _regex = CreateRegEx(); if (s == null) return false; return s != null && _regex.Match(s).Length > 0; } /// /// Convert HTML string to Plain Text without external libraries /// https://docs.microsoft.com/en-us/answers/questions/594274/convert-html-text-to-plain-text-in-c.html /// /// /// public static string HTMLToPlainText(this string htmlCode) { // Remove new lines since they are not visible in HTML htmlCode = htmlCode.Replace("\n", " "); // Remove tab spaces htmlCode = htmlCode.Replace("\t", " "); // Remove multiple white spaces from HTML htmlCode = Regex.Replace(htmlCode, "\\s+", " "); // Remove HEAD tag htmlCode = Regex.Replace(htmlCode, "", "", RegexOptions.IgnoreCase | RegexOptions.Singleline); // Remove any JavaScript htmlCode = Regex.Replace(htmlCode, "", "", RegexOptions.IgnoreCase | RegexOptions.Singleline); // Replace special characters like &, <, >, " etc. StringBuilder sbHTML = new StringBuilder(htmlCode); // Note: There are many more special characters, these are just // most common. You can add new characters in this arrays if needed string[] OldWords = {" ", "&", """, "<", ">", "®", "©", "•", "™","'"}; string[] NewWords = { " ", "&", "\"", "<", ">", "®", "©", "•", "â„¢", "\'" }; for (int i = 0; i < OldWords.Length; i++) { sbHTML.Replace(OldWords[i], NewWords[i]); } // Check if there are line breaks (
) or paragraph (

) sbHTML.Replace("
", "\n
"); sbHTML.Replace("
]*>", ""); // Remove external new lines plainText = plainText.Trim(); return plainText; } } }