diff --git a/.editorconfig b/.editorconfig index 0c64ba7..e0d113c 100644 --- a/.editorconfig +++ b/.editorconfig @@ -19,6 +19,10 @@ indent_size = 2 # 对于 JSON 和 YAML 文件,缩进大小为 2 个空格 [*.cs] dotnet_analyzer_diagnostic.severity = warning # 设置 C# 文件中所有 dotnet_analyzer_diagnostic 的严重性级别为 warning +[*.g.cs] +dotnet_analyzer_diagnostic.severity = none # 禁用所有代码分析规则 + + # ReSharper properties resharper_align_linq_query = true # 启用对LINQ查询的对齐 resharper_align_multiline_argument = true # 启用多行参数的对齐 diff --git a/Directory.Build.props b/Directory.Build.props index 00d57ad..9c56cc6 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -17,7 +17,7 @@ preview beta v - CA1707;IDE0005;IDE0008;IDE0010;IDE0028;IDE0055;IDE0160;IDE0300;IDE0305;RCS1141;RCS1142;RCS1181;S101;S1121;S1135;S125;S2094;S3604;S4663;SYSLIB1045;SA1010;RCS1123;SA1407;IDE0048;S1075;S3928 + CA1707;CA1720;CA5350;CA5351;IDE0005;IDE0008;IDE0010;IDE0028;IDE0048;IDE0055;IDE0160;IDE0300;IDE0305;RCS1123;RCS1141;RCS1142;RCS1181;S101;S1075;S1121;S1135;S125;S2094;S3604;S3928;S4663;SA1010;SA1407;SYSLIB1045 NSExt git https://github.com/nsnail/NSExt.git diff --git a/package.json b/package.json index 8c324cd..f067e31 100644 --- a/package.json +++ b/package.json @@ -11,4 +11,4 @@ "path": "node_modules/cz-git" } } -} +} \ No newline at end of file diff --git a/src/backend/NSExt/Extensions/StringExtensions.cs b/src/backend/NSExt/Extensions/StringExtensions.cs index fa4c2f1..c99a60b 100644 --- a/src/backend/NSExt/Extensions/StringExtensions.cs +++ b/src/backend/NSExt/Extensions/StringExtensions.cs @@ -1,10 +1,10 @@ -// ReSharper disable UnusedMember.Global -// ReSharper disable MemberCanBePrivate.Global - -#pragma warning disable CA1720 +using System.Numerics; +using System.Reflection; using System.Security.Cryptography; using System.Text.Json; using System.Web; +using Microsoft.CodeAnalysis.CSharp.Scripting; +using Microsoft.CodeAnalysis.Scripting; using NSExt.Constant; namespace NSExt.Extensions; @@ -12,9 +12,11 @@ namespace NSExt.Extensions; /// /// StringExtensions /// -#pragma warning disable CodeLinesAnalyzer -public static class StringExtensions +public static partial class StringExtensions { + private const string _CHARACTERS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + private static readonly Regex _regexIpV4 = RegexIpV4(); + /// /// aes加密 /// @@ -24,11 +26,11 @@ public static class StringExtensions { using var aes = System.Security.Cryptography.Aes.Create(); aes.Padding = PaddingMode.PKCS7; - aes.Mode = CipherMode.ECB; - aes.Key = key.Hex(); + aes.Mode = CipherMode.ECB; + aes.Key = key.Hex(); using var encryptor = aes.CreateEncryptor(); - var bytes = me.Hex(); - var decrypted = encryptor.TransformFinalBlock(bytes, 0, bytes.Length); + var bytes = me.Hex(); + var decrypted = encryptor.TransformFinalBlock(bytes, 0, bytes.Length); return decrypted.Base64(); } @@ -41,14 +43,72 @@ public static class StringExtensions { using var aes = System.Security.Cryptography.Aes.Create(); aes.Padding = PaddingMode.PKCS7; - aes.Mode = CipherMode.ECB; - aes.Key = key.Hex(); + aes.Mode = CipherMode.ECB; + aes.Key = key.Hex(); using var encryptor = aes.CreateDecryptor(); - var bytes = me.Base64De(); - var decrypted = encryptor.TransformFinalBlock(bytes, 0, bytes.Length); + var bytes = me.Base64De(); + var decrypted = encryptor.TransformFinalBlock(bytes, 0, bytes.Length); return decrypted.HexDe(); } + /// + /// 将指定的输入字符串进行Base62解码 + /// + /// ArgumentException + public static string Base62Decode(this string me) + { + BigInteger result = 0; + + foreach (var index in me.Select(c => _CHARACTERS.IndexOf(c))) + { + if (index < 0) + { + throw new ArgumentException("Invalid character in Base62 string."); + } + + result = result * 62 + index; + } + + // Convert BigInteger back to byte array and then to string + var bytes = result.ToByteArray(); + + // Handle the sign bit + if (bytes[^1] == 0) + { + Array.Resize(ref bytes, bytes.Length - 1); + } + + return Encoding.UTF8.GetString(bytes); + } + + /// + /// 将指定的输入字符串进行Base62编码 + /// + public static string Base62Encode(this string me) + { + // Convert string to byte array + var bytes = Encoding.UTF8.GetBytes(me); + + // Convert byte array to BigInteger for easier processing + var bigInteger = new BigInteger(bytes); + + if (bigInteger == 0) + { + return _CHARACTERS[0].ToString(); + } + + var result = new StringBuilder(); + + while (bigInteger > 0) + { + var remainder = (int)(bigInteger % 62); + bigInteger /= 62; + _ = result.Insert(0, _CHARACTERS[remainder]); + } + + return result.ToString(); + } + /// /// base64编码 /// @@ -81,6 +141,22 @@ public static class StringExtensions return e.GetString(me.Base64De()); } + /// + /// 解码避免转义的Base64 + /// + public static string Base64InUrlDecode(this string me) + { + return me.Replace("-", "+").Replace("_", "/"); + } + + /// + /// 编码避免转义的Base64 + /// + public static string Base64InUrlEncode(this string me) + { + return me.Replace("+", "-").Replace("/", "_"); + } + /// /// 将易于web传输的base64web字符串转换为原生base64 /// @@ -99,6 +175,14 @@ public static class StringExtensions return me.Replace("+", "-").Replace("/", "_").Replace("=", "."); } + /// + /// 计算Crc32 + /// + public static int Crc32(this string me) + { + return BitConverter.ToInt32(System.IO.Hashing.Crc32.Hash(Encoding.UTF8.GetBytes(me))); + } + /// /// 将字符串转换成日期对象 /// @@ -129,9 +213,7 @@ public static class StringExtensions /// 转换后的日期对象 public static DateTime DateTimeExactTry(this string me, string format, DateTime def) { - return !System.DateTime.TryParseExact(me, format, CultureInfo.CurrentCulture, DateTimeStyles.None, out var ret) - ? def - : ret; + return !System.DateTime.TryParseExact(me, format, CultureInfo.CurrentCulture, DateTimeStyles.None, out var ret) ? def : ret; } /// @@ -142,9 +224,7 @@ public static class StringExtensions /// 转换后的日期对象 public static DateTime DateTimeTry(this string me, DateTime def) { - return !System.DateTime.TryParse(me, CultureInfo.InvariantCulture, DateTimeStyles.None, out var ret) - ? def - : ret; + return !System.DateTime.TryParse(me, CultureInfo.InvariantCulture, DateTimeStyles.None, out var ret) ? def : ret; } /// @@ -196,6 +276,15 @@ public static class StringExtensions return !System.Enum.TryParse(typeof(T), name, out var ret) ? def : (T)ret; } + /// + /// 执行C#代码 + /// + public static Task ExecuteCSharpCodeAsync(this string me, Assembly[] assemblies, params string[] importNamespaces) + { + // 使用 Roslyn 编译并执行代码 + return CSharpScript.EvaluateAsync(me, ScriptOptions.Default.WithReferences(assemblies).WithImports(importNamespaces)); + } + /// /// string to float /// @@ -255,16 +344,13 @@ public static class StringExtensions /// hash摘要的16进制文本形式(无连字符小写) public static string HmacSha1(this string me, string secret, Encoding e) { - #pragma warning disable CA5350 using var hmacSha1 = new HMACSHA1(e.GetBytes(secret)); - #pragma warning restore CA5350 - #if NET9_0_OR_GREATER + +#if NET9_0_OR_GREATER return Convert.ToHexStringLower(hmacSha1.ComputeHash(e.GetBytes(me))); - #else - return BitConverter.ToString(hmacSha1.ComputeHash(e.GetBytes(me))) - .Replace("-", string.Empty) - .ToLower(CultureInfo.CurrentCulture); - #endif +#else + return BitConverter.ToString(hmacSha1.ComputeHash(e.GetBytes(me))).Replace("-", string.Empty).ToLower(CultureInfo.CurrentCulture); +#endif } /// @@ -344,16 +430,19 @@ public static class StringExtensions // 一个合法的Base64,有着以下特征: // 字符串的长度为4的整数倍。 // 字符串的符号取值只能在A -Z, a -z, 0 -9, +, /, =共计65个字符中,且 = 如果出现就必须在结尾出现。 - if (!me.All(x => x.IsBase64Character())) { + if (!me.All(x => x.IsBase64Character())) + { return false; } - if (me.Length % 4 != 0) { + if (me.Length % 4 != 0) + { return false; } var firstEqualSignPos = me.IndexOf('='); - if (firstEqualSignPos < 0) { + if (firstEqualSignPos < 0) + { return true; } @@ -361,20 +450,31 @@ public static class StringExtensions return lastEqualSignPos == me.Length - 1 && me[firstEqualSignPos..lastEqualSignPos].All(x => x == '='); } + /// + /// 是否IPV4地址 + /// + public static bool IsIpV4(this string me) + { + return _regexIpV4.IsMatch(me); + } + /// /// 是否json字符串 /// /// me public static bool IsJsonString(this string me) { - if (me.NullOrEmpty()) { + if (me.NullOrEmpty()) + { return false; } - try { + try + { _ = JsonDocument.Parse(me); } - catch { + catch + { return false; } @@ -407,15 +507,13 @@ public static class StringExtensions /// hash摘要的16进制文本形式(无连字符小写) public static string Md5(this string me, Encoding e) { - #pragma warning disable CA5351 - #if NET9_0_OR_GREATER +#if NET9_0_OR_GREATER return Convert.ToHexStringLower(MD5.HashData(e.GetBytes(me))); - #else +#else return BitConverter.ToString(MD5.HashData(e.GetBytes(me))) - #pragma warning restore CA5351 - .Replace("-", string.Empty) - .ToLower(CultureInfo.CurrentCulture); - #endif + .Replace("-", string.Empty) + .ToLower(CultureInfo.CurrentCulture); +#endif } /// @@ -496,15 +594,13 @@ public static class StringExtensions /// hash摘要的16进制文本形式(无连字符小写) public static string Sha1(this string me, Encoding e) { - #pragma warning disable CA5350 - #if NET9_0_OR_GREATER +#if NET9_0_OR_GREATER return Convert.ToHexStringLower(SHA1.HashData(e.GetBytes(me))); - #else +#else return BitConverter.ToString(SHA1.HashData(e.GetBytes(me))) - #pragma warning restore CA5350 - .Replace("-", string.Empty) - .ToLower(CultureInfo.CurrentCulture); - #endif + .Replace("-", string.Empty) + .ToLower(CultureInfo.CurrentCulture); +#endif } /// @@ -520,7 +616,8 @@ public static class StringExtensions /// public static string Sub(this string me, int startIndex, int length) { - if (startIndex + length > me.Length) { + if (startIndex + length > me.Length) + { length = me.Length - startIndex; } @@ -540,10 +637,7 @@ public static class StringExtensions /// public static string ToLowerCamelCase(this string me) { - return string.IsNullOrWhiteSpace(me) - ? me - : string.Concat( // - me[0].ToString(CultureInfo.InvariantCulture).ToLowerInvariant(), me.AsSpan(1)); + return string.IsNullOrWhiteSpace(me) ? me : string.Concat(me[0].ToString(CultureInfo.InvariantCulture).ToLowerInvariant(), me.AsSpan(1)); } /// @@ -554,6 +648,14 @@ public static class StringExtensions return string.IsNullOrWhiteSpace(me) ? me : string.Concat(me[0].ToString().ToUpperInvariant(), me.AsSpan(1)); } + /// + /// 去掉前部字符串 + /// + public static string TrimPrefix(this string me, string clearStr) + { + return Regex.Replace(me, $"^{clearStr}", string.Empty); + } + /// /// 将连续多个空格替换成一个空格 /// @@ -565,24 +667,25 @@ public static class StringExtensions return ret == me ? ret : ret.TrimSpaces(); } + /// + /// 去掉尾部字符串 + /// + public static string TrimSuffix(this string me, string clearStr) + { + return Regex.Replace(me, $"{clearStr}$", string.Empty); + } + /// /// 将\ux0000 、 %u0000 、 &#x0000; 编码转换成可读字符串 /// public static string UnicodeDe(this string me) { +#pragma warning disable S3358, RCS1238 const string replacement = "&#x$1;"; - if (me.Contains(@"\u")) { - return Regexes.RegexBacksLantUnicode.Replace(me, replacement).HtmlDe(); - } - - // ReSharper disable once ConvertIfStatementToReturnStatement - #pragma warning disable IDE0046 - if (me.Contains("%u")) { - #pragma warning restore IDE0046 - return Regexes.RegexPercentUnicode.Replace(me, replacement).HtmlDe(); - } - - return me.HtmlDe(); + return !me.Contains(@"\u") + ? me.Contains("%u") ? Regexes.RegexPercentUnicode.Replace(me, replacement).HtmlDe() : me.HtmlDe() + : Regexes.RegexBacksLantUnicode.Replace(me, replacement).HtmlDe(); +#pragma warning restore S3358, RCS1238 } /// @@ -614,16 +717,15 @@ public static class StringExtensions /// hash摘要的16进制文本形式(无连字符小写) private static string Md5Hmac(this string me, string key, Encoding e) { - #pragma warning disable CA5351 using var md5Hmac = new HMACMD5(e.GetBytes(key)); - #pragma warning restore CA5351 - #if NET9_0_OR_GREATER + +#if NET9_0_OR_GREATER return Convert.ToHexStringLower(md5Hmac.ComputeHash(e.GetBytes(me))); - #else - return BitConverter.ToString(md5Hmac.ComputeHash(e.GetBytes(me))) - .Replace("-", string.Empty) - .ToLower(CultureInfo.CurrentCulture); - #endif +#else + return BitConverter.ToString(md5Hmac.ComputeHash(e.GetBytes(me))).Replace("-", string.Empty).ToLower(CultureInfo.CurrentCulture); +#endif } -} -#pragma warning restore CodeLinesAnalyzer \ No newline at end of file + + [GeneratedRegex(@"^(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|[0-1]?[0-9]{1,2})){3}$")] + private static partial Regex RegexIpV4(); +} \ No newline at end of file diff --git a/src/backend/NSExt/NSExt.csproj b/src/backend/NSExt/NSExt.csproj index 5969fdd..0d9a425 100644 --- a/src/backend/NSExt/NSExt.csproj +++ b/src/backend/NSExt/NSExt.csproj @@ -7,7 +7,9 @@ + +