using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Numerics; using System.Reflection; using System.Runtime.CompilerServices; using System.Text.RegularExpressions; namespace PCL.Core.Utils.Exts; public static class StringConvertExtension { public static object? Convert(string? value, Type targetType) { ArgumentNullException.ThrowIfNull(targetType); if (targetType == typeof(string)) return value; if (value is null) { if (!targetType.IsValueType || Nullable.GetUnderlyingType(targetType) is not null) return null; return Activator.CreateInstance(targetType); } var converter = TypeDescriptor.GetConverter(targetType); if (converter.CanConvertFrom(typeof(string))) { var c = converter.ConvertFromInvariantString(value); return c; } if (typeof(IConvertible).IsAssignableFrom(targetType)) { // ReSharper disable once RedundantSuppressNullableWarningExpression var changed = System.Convert.ChangeType(value, targetType, CultureInfo.InvariantCulture)!; return changed; } if (targetType.IsEnum) return Enum.Parse(targetType, value, ignoreCase: true); var parse = targetType.GetMethod("Parse", BindingFlags.Public | BindingFlags.Static, binder: null, types: [typeof(string)], modifiers: null); if (parse is not null) return parse.Invoke(null, [value]); throw new NotSupportedException($"无法将字符串转换为类型 {targetType.FullName}"); } public static T? Convert(this string? value) { var obj = Convert(value, typeof(T)); if (obj is null) return default; return (T)obj; } } public static class StringExtension { public static string? ConvertToString(object? obj) { if (obj is null) return null; if (obj is string s) return s; var converter = TypeDescriptor.GetConverter(obj.GetType()); if (converter.CanConvertTo(typeof(string))) { object? o = converter.ConvertToInvariantString(obj); return o as string; } if (obj is IFormattable fmt) return fmt.ToString(null, CultureInfo.InvariantCulture); return obj.ToString(); } public static string? ConvertToString(this T? value) => ConvertToString((object?)value); private static readonly char[] _B36Map = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray(); extension(string input) { public string FromB10ToB36() { var n = BigInteger.Parse(input); var s = new List(); while (n > 0) { var i = (n % 36).ToByteArray()[0]; s.Add(_B36Map[i]); n /= 36; } s.Reverse(); return string.Join("", s); } public string FromB36ToB10() { var ns = input.Select(c => (c is >= '0' and <= '9') ? c - '0' : c - 'A' + 10).ToArray(); var nb = ns.Aggregate(new BigInteger(0), (n, i) => n * 36 + i); return nb.ToString(); } } private static readonly char[] _B32Map = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ".ToCharArray(); extension(string input) { /// /// 将 Base10 文本重新编码为 Base32 文本。 /// public string FromB10ToB32() { var n = BigInteger.Parse(input); var s = new List(); while (n > 0) { var i = (n % 32).ToByteArray()[0]; s.Add(_B32Map[i]); n /= 32; } s.Reverse(); return string.Join("", s); } /// /// 将 Base32 文本重新编码为 Base10 文本。 /// public string FromB32ToB10() { var ns = input.Select(Parse).ToArray(); var nb = ns.Aggregate(new BigInteger(0), (n, i) => n * 32 + i); return nb.ToString(); int Parse(char c) => c switch { >= '2' and <= '9' => c - '2', >= 'A' and <= 'H' => c - 'A' + 8, >= 'J' and <= 'N' => c - 'J' + 16, >= 'P' and <= 'Z' => c - 'P' + 21, _ => throw new ArgumentOutOfRangeException(nameof(input), $"Character '{c}' out of Base32 range") }; } public string FromB64ToB64UrlSafe() => input.Replace("+", "-").Replace("/", "_"); public string FromB64UrlSafeToB64() => input.Replace("-", "+").Replace("_", "/"); public byte[] FromB64ToBytes() { switch (input.Length % 4) { case 3: input += "==="; break; case 2: input += "=="; break; case 1: input += "="; break; } return Convert.FromBase64String(input); } public byte[] FromB64UrlSafeToBytes() => input.FromB64UrlSafeToB64().FromB64ToBytes(); } extension(string input) { public T ParseToEnum() where T : struct, Enum { if (String.IsNullOrWhiteSpace(input)) { return (T)(object)0; } else if (int.TryParse(input, out int numericValue)) { return (T)(object)numericValue; } else { return Enum.Parse(input, true); } } } extension([NotNullWhen(false)] string? value) { /// /// 的扩展方法。 /// public bool IsNullOrEmpty() => string.IsNullOrEmpty(value); /// /// 的扩展方法。 /// public bool IsNullOrWhiteSpace() => string.IsNullOrWhiteSpace(value); } /// 文本 extension(string? input) { /// /// 当文本为空时返回替代文本,否则返回原来的文本。 /// /// 替代文本 public string ReplaceNullOrEmpty(string? replacement = null) => string.IsNullOrEmpty(input) ? (replacement ?? string.Empty) : input; /// /// 替换指定文本中的所有换行符。 /// /// 用于替换的文本 /// 替换后的文本 public string ReplaceLineBreak(string replacement = " ") => input?.Replace(RegexPatterns.NewLine, replacement) ?? string.Empty; /// /// 替换指定文本中所有匹配正则表达式的部分。 /// /// 正则表达式 /// 用于替换的文本 /// 替换后的文本 [return: NotNullIfNotNull(nameof(input))] public string? Replace(Regex regex, string replacement) => input is null ? null : regex.Replace(input, replacement); /// /// 判断指定文本是否能成功匹配正则表达式。 /// /// 正则表达式 /// 若匹配成功则为 true,若文本为 null 或匹配不成功则为 false public bool IsMatch(Regex regex) => input is not null && regex.IsMatch(input); } extension(string str) { /// /// 查找并返回指定文本中所有与正则表达式匹配的部分。 /// public List RegexSearch(Regex regex) { var result = new List(); var regexSearchRes = regex.Matches(str); if (regexSearchRes.Count == 0) return result; result.AddRange(from Match item in regexSearchRes select item.Value); return result; } /// /// 判断指定文本是否在 ASCII 范围内。 /// // ReSharper disable once InconsistentNaming public bool IsASCII() { return str.All(c => c < 128); } public bool StartsWithF(string prefix, bool ignoreCase = false) => str.StartsWith(prefix, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); public bool EndsWithF(string suffix, bool ignoreCase = false) => str.EndsWith(suffix, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); public bool ContainsF(string subStr, bool ignoreCase = false) => str.Contains(subStr, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); public int IndexOfF(string subStr, bool ignoreCase = false) => str.IndexOf(subStr, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); public int IndexOfF(string subStr, int startIndex, bool ignoreCase = false) => str.IndexOf(subStr, startIndex, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); public int LastIndexOfF(string subStr, bool ignoreCase = false) => str.LastIndexOf(subStr, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); public int LastIndexOfF(string subStr, int startIndex, bool ignoreCase = false) => str.LastIndexOf(subStr, startIndex, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); } extension(string hex) { [MethodImpl(MethodImplOptions.AggressiveInlining)] public byte[] HexToBytes() => Convert.FromHexString(hex); } }