reactredux/webapi/Extensions/StringExtensions.cs

345 lines
14 KiB
C#

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 {
/// <summary>
/// SQL Like implementation
/// </summary>
/// <param name="text"></param>
/// <param name="wildcardedText"></param>
/// <returns></returns>
public static bool Like(this string text, string wildcardedText) {
text = text ?? "";
wildcardedText = wildcardedText ?? "";
return Regex.IsMatch(text, wildcardedText.WildcardToRegular(), RegexOptions.IgnoreCase | RegexOptions.Multiline);
}
/// <summary>
/// Converts wildcarded string tgo regex
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
private static string WildcardToRegular(this string value) =>
$"^{Regex.Escape(value).Replace("\\?", ".").Replace("\\*", ".*")}$";
/// <summary>
/// VB.Net Left implementation
/// </summary>
/// <param name="s"></param>
/// <param name="count"></param>
/// <returns></returns>
public static string Left(this string s, int count) {
return s.Substring(0, count);
}
/// <summary>
/// VB.Net Right implementation
/// </summary>
/// <param name="s"></param>
/// <param name="count"></param>
/// <returns></returns>
public static string Right(this string s, int count) {
return s.Substring(s.Length - count, count);
}
/// <summary>
/// VB.Net Mid implementation
/// </summary>
/// <param name="s"></param>
/// <param name="index"></param>
/// <param name="count"></param>
/// <returns></returns>
public static string Mid(this string s, int index, int count) {
return s.Substring(index, count);
}
/// <summary>
/// VB.Net ToInteger implementation
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public static int ToInteger(this string s) {
var integerValue = 0;
int.TryParse(s, out integerValue);
return integerValue;
}
/// <summary>
/// VB.Net IsInteger implementations
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
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<T>(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<T>(this string input) where T : struct => !string.IsNullOrWhiteSpace(input) ? input.ToEnum<T>() : 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 == "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();
}
/// <summary>
///
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
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<Uri> ExtractUrls(this string s) {
var urls = new List<Uri>();
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);
/// <summary>
/// Adds elipsis
/// </summary>
/// <param name="s"></param>
/// <param name="length"></param>
/// <returns></returns>
public static string Excerpt(this string s, int length = 60) =>
string.IsNullOrEmpty(s) || s.Length < length ? s : s.Substring(0, length - 3) + "...";
/// <summary>
/// Converts JSON string to object
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="s"></param>
/// <returns></returns>
public static T? ToObject<T>(this string s) => JsonSerializer.Deserialize<T>(s, new JsonSerializerOptions {
PropertyNameCaseInsensitive = true
});
/// <summary>
/// Adapted from .Net [EmailAddres] model validation attribute
/// https://referencesource.microsoft.com/#System.ComponentModel.DataAnnotations/DataAnnotations/EmailAddressAttribute.cs,17f9a2457ddc8d93
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 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
/// </summary>
/// <param name="htmlCode"></param>
/// <returns></returns>
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, "<head.*?</head>", "", RegexOptions.IgnoreCase | RegexOptions.Singleline);
// Remove any JavaScript
htmlCode = Regex.Replace(htmlCode, "<script.*?</script>", "", 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 = {"&nbsp;", "&amp;", "&quot;", "&lt;", "&gt;", "&reg;", "&copy;", "&bull;", "&trade;","&#39;"};
string[] NewWords = { " ", "&", "\"", "<", ">", "®", "©", "•", "™", "\'" };
for (int i = 0; i < OldWords.Length; i++) {
sbHTML.Replace(OldWords[i], NewWords[i]);
}
// Check if there are line breaks (<br>) or paragraph (<p>)
sbHTML.Replace("<br>", "\n<br>");
sbHTML.Replace("<br ", "\n<br ");
sbHTML.Replace("<p ", "\n<p ");
// Finally, remove all HTML tags and return plain text
var plainText = Regex.Replace(sbHTML.ToString(), "<[^>]*>", "");
// Remove external new lines
plainText = plainText.Trim();
return plainText;
}
}
}