diff --git a/SageTools/Extension/Stream.cs b/SageTools/Extension/Stream.cs
new file mode 100644
index 0000000..93d08c8
--- /dev/null
+++ b/SageTools/Extension/Stream.cs
@@ -0,0 +1,35 @@
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace SageTools.Extension
+{
+ public static partial class Extension
+ {
+ ///
+ /// 将流读为字符串
+ /// 注:默认使用UTF-8编码
+ ///
+ /// 流
+ /// 指定编码
+ ///
+ public static async Task ReadToStringAsync(this Stream stream, Encoding encoding = null)
+ {
+ encoding ??= Encoding.UTF8;
+
+ if (stream.CanSeek)
+ {
+ stream.Seek(0, SeekOrigin.Begin);
+ }
+
+ var resStr = await new StreamReader(stream, encoding).ReadToEndAsync();
+
+ if (stream.CanSeek)
+ {
+ stream.Seek(0, SeekOrigin.Begin);
+ }
+
+ return resStr;
+ }
+ }
+}
\ No newline at end of file
diff --git a/SageTools/Extension/String.cs b/SageTools/Extension/String.cs
index a137f95..5212dd1 100644
--- a/SageTools/Extension/String.cs
+++ b/SageTools/Extension/String.cs
@@ -1,11 +1,17 @@
using System;
using System.Collections.Generic;
using System.Data;
+using System.Globalization;
using System.IO;
+using System.Linq;
+using System.Net;
+using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
+using System.Xml.Linq;
+using System.Xml;
namespace SageTools.Extension
{
@@ -24,14 +30,17 @@ public static string SubSpecifiedLengthStr(this string str, int length, bool ret
{
return str;
}
+
if (length == 0)
{
return string.Empty;
}
+
if (length < 0 || length > str.Length)
{
return returnAllOrThrowWhenIndexOutOfRange ? str : throw new IndexOutOfRangeException();
}
+
return str.Substring(length);
}
@@ -109,6 +118,7 @@ public static string ReplaceByEmpty(this string str, params string[] values)
{
str = str.Replace(oldValue, "");
}
+
return str;
}
@@ -310,7 +320,8 @@ public static string Md5(this string str)
///
/// 是否是正确的email地址
///
- public static bool IsValidEmail(this string obj) => Regex.IsMatch(obj, "^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$");
+ public static bool IsValidEmail(this string obj) =>
+ Regex.IsMatch(obj, "^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$");
///
/// 是否是正确的ip地址
@@ -343,14 +354,14 @@ public static bool IsUrl(this string strUrl) => Regex.IsMatch(strUrl,
///
/// 满足条件则添加
///
-
public static StringBuilder AppendIf(this StringBuilder @this, Func predicate, params T[] values)
{
- foreach (T obj in values)
+ foreach (var obj in values)
{
if (predicate(obj))
@this.Append((object) obj);
}
+
return @this;
}
@@ -359,11 +370,12 @@ public static StringBuilder AppendIf(this StringBuilder @this, Func
///
public static StringBuilder AppendLineIf(this StringBuilder @this, Func predicate, params T[] values)
{
- foreach (T obj in values)
+ foreach (var obj in values)
{
if (predicate(obj))
@this.AppendLine(obj.ToString());
}
+
return @this;
}
@@ -404,5 +416,470 @@ public static StringBuilder AppendLineFormat(this StringBuilder @this, string fo
/// 从右截取指定字符,超出长度则截取到开头
///
public static string Right(this string @this, int length) => @this.RightSafe(length);
+
+ ///
+ /// 转换为日期格式
+ ///
+ public static DateTime ToDateTime(this string @this) => Convert.ToDateTime(@this);
+
+ ///
+ /// 转为字节数组
+ ///
+ /// base64字符串
+ ///
+ public static byte[] ToBytes_FromBase64Str(this string base64Str)
+ {
+ return Convert.FromBase64String(base64Str);
+ }
+
+ ///
+ /// 转换为MD5加密后的字符串(默认加密为32位)
+ ///
+ ///
+ ///
+ public static string ToMD5String(this string str)
+ {
+ var md5 = MD5.Create();
+ var inputBytes = Encoding.UTF8.GetBytes(str);
+ var hashBytes = md5.ComputeHash(inputBytes);
+
+ var sb = new StringBuilder();
+ foreach (var t in hashBytes)
+ {
+ sb.Append(t.ToString("x2"));
+ }
+
+ md5.Dispose();
+
+ return sb.ToString();
+ }
+
+ ///
+ /// 转换为MD5加密后的字符串(16位)
+ ///
+ ///
+ ///
+ public static string ToMD5String16(this string str)
+ {
+ return str.ToMD5String().Substring(8, 16);
+ }
+
+ ///
+ /// Base64加密
+ /// 注:默认采用UTF8编码
+ ///
+ /// 待加密的明文
+ /// 加密后的字符串
+ public static string Base64Encode(this string source)
+ {
+ return Base64Encode(source, Encoding.UTF8);
+ }
+
+ ///
+ /// Base64加密
+ ///
+ /// 待加密的明文
+ /// 加密采用的编码方式
+ ///
+ public static string Base64Encode(this string source, Encoding encoding)
+ {
+ string encode;
+ var bytes = encoding.GetBytes(source);
+ try
+ {
+ encode = Convert.ToBase64String(bytes);
+ }
+ catch
+ {
+ encode = source;
+ }
+
+ return encode;
+ }
+
+ ///
+ /// Base64解密
+ /// 注:默认使用UTF8编码
+ ///
+ /// 待解密的密文
+ /// 解密后的字符串
+ public static string Base64Decode(this string result)
+ {
+ return Base64Decode(result, Encoding.UTF8);
+ }
+
+ ///
+ /// Base64解密
+ ///
+ /// 待解密的密文
+ /// 解密采用的编码方式,注意和加密时采用的方式一致
+ /// 解密后的字符串
+ public static string Base64Decode(this string result, Encoding encoding)
+ {
+ string decode;
+ var bytes = Convert.FromBase64String(result);
+ try
+ {
+ decode = encoding.GetString(bytes);
+ }
+ catch
+ {
+ decode = result;
+ }
+
+ return decode;
+ }
+
+ ///
+ /// Base64Url编码
+ ///
+ /// 待编码的文本字符串
+ /// 编码的文本字符串
+ public static string Base64UrlEncode(this string text)
+ {
+ var plainTextBytes = Encoding.UTF8.GetBytes(text);
+ var base64 = Convert.ToBase64String(plainTextBytes).Replace('+', '-').Replace('/', '_').TrimEnd('=');
+
+ return base64;
+ }
+
+ ///
+ /// Base64Url解码
+ ///
+ /// 使用Base64Url编码后的字符串
+ /// 解码后的内容
+ public static string Base64UrlDecode(this string base64UrlStr)
+ {
+ base64UrlStr = base64UrlStr.Replace('-', '+').Replace('_', '/');
+ switch (base64UrlStr.Length % 4)
+ {
+ case 2:
+ base64UrlStr += "==";
+ break;
+ case 3:
+ base64UrlStr += "=";
+ break;
+ }
+
+ var bytes = Convert.FromBase64String(base64UrlStr);
+
+ return Encoding.UTF8.GetString(bytes);
+ }
+
+ ///
+ /// 计算SHA1摘要
+ /// 注:默认使用UTF8编码
+ ///
+ /// 字符串
+ ///
+ public static byte[] ToSHA1Bytes(this string str)
+ {
+ return str.ToSHA1Bytes(Encoding.UTF8);
+ }
+
+ ///
+ /// 计算SHA1摘要
+ ///
+ /// 字符串
+ /// 编码
+ ///
+ public static byte[] ToSHA1Bytes(this string str, Encoding encoding)
+ {
+ SHA1 sha1 = new SHA1CryptoServiceProvider();
+ var inputBytes = encoding.GetBytes(str);
+ var outputBytes = sha1.ComputeHash(inputBytes);
+
+ return outputBytes;
+ }
+
+ ///
+ /// 转为SHA1哈希加密字符串
+ /// 注:默认使用UTF8编码
+ ///
+ /// 字符串
+ ///
+ public static string ToSHA1String(this string str)
+ {
+ return str.ToSHA1String(Encoding.UTF8);
+ }
+
+ ///
+ /// 转为SHA1哈希
+ ///
+ /// 字符串
+ /// 编码
+ ///
+ public static string ToSHA1String(this string str, Encoding encoding)
+ {
+ var sha1Bytes = str.ToSHA1Bytes(encoding);
+ var resStr = BitConverter.ToString(sha1Bytes);
+ return resStr.Replace("-", "").ToLower();
+ }
+
+ ///
+ /// SHA256加密
+ ///
+ /// 字符串
+ ///
+ public static string ToSHA256String(this string str)
+ {
+ var bytes = Encoding.UTF8.GetBytes(str);
+ var hash = SHA256.Create().ComputeHash(bytes);
+
+ var builder = new StringBuilder();
+ foreach (var t in hash)
+ {
+ builder.Append(t.ToString("x2"));
+ }
+
+ return builder.ToString();
+ }
+
+ ///
+ /// HMACSHA256算法
+ ///
+ /// 内容
+ /// 密钥
+ ///
+ public static string ToHMACSHA256String(this string text, string secret)
+ {
+ secret ??= "";
+ var keyByte = Encoding.UTF8.GetBytes(secret);
+ var messageBytes = Encoding.UTF8.GetBytes(text);
+ using var hmacsha256 = new HMACSHA256(keyByte);
+ var hashmessage = hmacsha256.ComputeHash(messageBytes);
+ return Convert.ToBase64String(hashmessage).Replace('+', '-').Replace('/', '_').TrimEnd('=');
+ }
+
+ ///
+ /// string转int
+ ///
+ /// 字符串
+ ///
+ public static int ToInt(this string str)
+ {
+ str = str.Replace("\0", "");
+ if (string.IsNullOrEmpty(str))
+ return 0;
+ return Convert.ToInt32(str);
+ }
+
+ ///
+ /// string转long
+ ///
+ /// 字符串
+ ///
+ public static long ToLong(this string str)
+ {
+ str = str.Replace("\0", "");
+ if (string.IsNullOrEmpty(str))
+ return 0;
+
+ return Convert.ToInt64(str);
+ }
+
+ ///
+ /// 二进制字符串转为Int
+ ///
+ /// 二进制字符串
+ ///
+ public static int ToInt_FromBinString(this string str)
+ {
+ return Convert.ToInt32(str, 2);
+ }
+
+ ///
+ /// 将16进制字符串转为Int
+ ///
+ /// 数值
+ ///
+ public static int ToInt0X(this string str)
+ {
+ int num = Int32.Parse(str, NumberStyles.HexNumber);
+ return num;
+ }
+
+ ///
+ /// 转换为double
+ ///
+ /// 字符串
+ ///
+ public static double ToDouble(this string str)
+ {
+ return Convert.ToDouble(str);
+ }
+
+ ///
+ /// string转byte[]
+ ///
+ /// 字符串
+ ///
+ public static byte[] ToBytes(this string str)
+ {
+ return Encoding.Default.GetBytes(str);
+ }
+
+ ///
+ /// string转byte[]
+ ///
+ /// 字符串
+ /// 需要的编码
+ ///
+ public static byte[] ToBytes(this string str, Encoding theEncoding)
+ {
+ return theEncoding.GetBytes(str);
+ }
+
+ ///
+ /// 将16进制字符串转为Byte数组
+ ///
+ /// 16进制字符串(2个16进制字符表示一个Byte)
+ ///
+ public static byte[] To0XBytes(this string str)
+ {
+ List resBytes = new List();
+ for (int i = 0; i < str.Length; i = i + 2)
+ {
+ string numStr = $@"{str[i]}{str[i + 1]}";
+ resBytes.Add((byte) numStr.ToInt0X());
+ }
+
+ return resBytes.ToArray();
+ }
+
+ ///
+ /// 将ASCII码形式的字符串转为对应字节数组
+ /// 注:一个字节一个ASCII码字符
+ ///
+ /// 字符串
+ ///
+ public static byte[] ToASCIIBytes(this string str)
+ {
+ return str.ToList().Select(x => (byte) x).ToArray();
+ }
+
+ ///
+ /// 删除Json字符串中键中的@符号
+ ///
+ /// json字符串
+ ///
+ public static string RemoveAt(this string jsonStr)
+ {
+ Regex reg = new Regex("\"@([^ \"]*)\"\\s*:\\s*\"(([^ \"]+\\s*)*)\"");
+ string strPatten = "\"$1\":\"$2\"";
+ return reg.Replace(jsonStr, strPatten);
+ }
+
+ ///
+ /// json数据转实体类,仅仅应用于单个实体类,速度非常快
+ ///
+ /// 泛型参数
+ /// json字符串
+ ///
+ public static T ToEntity(this string json)
+ {
+ if (string.IsNullOrEmpty(json))
+ return default(T);
+
+ var type = typeof(T);
+ var obj = Activator.CreateInstance(type, null);
+
+ foreach (var item in type.GetProperties())
+ {
+ var info = obj.GetType().GetProperty(item.Name);
+ var pattern = "\"" + item.Name + "\":\"(.*?)\"";
+ foreach (Match match in Regex.Matches(json, pattern))
+ {
+ switch (item.PropertyType.ToString())
+ {
+ case "System.String":
+ info?.SetValue(obj, match.Groups[1].ToString(), null);
+ break;
+ case "System.Int32":
+ info?.SetValue(obj, match.Groups[1].ToString().ToInt(), null);
+ break;
+ case "System.Int64":
+ info?.SetValue(obj, Convert.ToInt64(match.Groups[1].ToString()), null);
+ break;
+ case "System.DateTime":
+ info?.SetValue(obj, Convert.ToDateTime(match.Groups[1].ToString()), null);
+ break;
+ }
+ }
+ }
+
+ return (T) obj;
+ }
+
+ ///
+ /// 转为首字母大写
+ ///
+ /// 字符串
+ ///
+ public static string ToFirstUpperStr(this string str)
+ {
+ return str[..1].ToUpper() + str[1..];
+ }
+
+ ///
+ /// 转为首字母小写
+ ///
+ /// 字符串
+ ///
+ public static string ToFirstLowerStr(this string str)
+ {
+ return str[..1].ToLower() + str[1..];
+ }
+
+ ///
+ /// 转为网络终结点IPEndPoint
+ /// =
+ /// 字符串
+ ///
+ public static IPEndPoint ToIPEndPoint(this string str)
+ {
+ IPEndPoint iPEndPoint = null;
+ try
+ {
+ var strArray = str.Split(':').ToArray();
+ var addr = strArray[0];
+ var port = Convert.ToInt32(strArray[1]);
+ iPEndPoint = new IPEndPoint(IPAddress.Parse(addr), port);
+ }
+ catch
+ {
+ iPEndPoint = null;
+ }
+
+ return iPEndPoint;
+ }
+
+ ///
+ /// 将枚举类型的文本转为枚举类型
+ ///
+ /// 枚举类型
+ /// 枚举文本
+ ///
+ public static TEnum ToEnum(this string enumText) where TEnum : struct
+ {
+ System.Enum.TryParse(enumText, out TEnum value);
+
+ return value;
+ }
+
+ ///
+ /// 是否为弱密码
+ /// 注:密码必须包含数字、小写字母、大写字母和其他符号中的两种并且长度大于8
+ ///
+ /// 密码
+ ///
+ public static bool IsWeakPwd(this string pwd)
+ {
+ if (pwd.IsNullOrEmpty())
+ throw new Exception("pwd不能为空");
+
+ const string pattern = "(^[0-9]+$)|(^[a-z]+$)|(^[A-Z]+$)|(^.{0,8}$)";
+ return Regex.IsMatch(pwd, pattern);
+ }
}
}
\ No newline at end of file
diff --git a/SageTools/Utils/ExtensionUtils.cs b/SageTools/Utils/ExtensionUtils.cs
new file mode 100644
index 0000000..5f8ff5e
--- /dev/null
+++ b/SageTools/Utils/ExtensionUtils.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Threading.Tasks;
+
+namespace SageTools.Utils
+{
+ ///
+ /// 工具类扩展方法类
+ ///
+ public class ExtensionUtils
+ {
+ ///
+ /// 同步等待重试
+ ///
+ ///
+ /// 执行方法
+ /// 跳出重试条件,当为true时,终止重试
+ /// 重试次数
+ /// 重试间隔时间(ms)
+ /// 执行出错
+ public static T DelayRetry(Func executeFunc, Func breakConditionFunc, int retryCount = 1, int milliseconds = 1000)
+ {
+ var res = default(T);
+ while (retryCount > 0)
+ {
+ retryCount--;
+ res = executeFunc.Invoke();
+ if (breakConditionFunc.Invoke(res)) break;
+ Task.Delay(milliseconds).Wait();
+ }
+
+ return res;
+ }
+
+ ///
+ /// 异步等待重试
+ ///
+ ///
+ /// 执行方法
+ /// 跳出重试条件,当为true时,终止重试
+ /// 重试次数
+ /// 重试间隔时间(ms)
+ /// 执行出错
+ public static async Task DelayRetryAsync(Func> executeFunc, Func breakConditionFunc, int retryCount = 1, int milliseconds = 1000)
+ {
+ var res = default(T);
+ while (retryCount > 0)
+ {
+ retryCount--;
+ res = await executeFunc.Invoke();
+ if (breakConditionFunc.Invoke(res)) break;
+ await Task.Delay(milliseconds);
+ }
+
+ return res;
+ }
+
+ ///
+ ///同步方法重试(异常情况也重试)
+ ///
+ ///
+ /// 执行的方法
+ /// 跳出重试条件,当为true时,终止重试
+ /// 重试次数
+ ///
+ public static T ActionRetry(Func action, Func breakConditionFunc, int retryCount = 1)
+ {
+ var res = default(T);
+ while (retryCount > 0)
+ {
+ retryCount--;
+ try
+ {
+ res = action.Invoke();
+ if (breakConditionFunc.Invoke(res)) break;
+ }
+ catch
+ {
+ // ignore
+ }
+ }
+
+ return res;
+ }
+
+ ///
+ /// 异步方法重试(异常情况也重试)
+ ///
+ ///
+ /// 执行的方法
+ /// 跳出重试条件,当为true时,终止重试
+ /// 重试次数
+ ///
+ public static async Task ActionRetryAsync(Func> action, Func breakConditionFunc, int retryCount = 1)
+ {
+ var res = default(T);
+ while (retryCount > 0)
+ {
+ retryCount--;
+ try
+ {
+ res = await action.Invoke();
+ if (breakConditionFunc.Invoke(res)) break;
+ }
+ catch
+ {
+ // ignore
+ }
+ }
+
+ return res;
+ }
+ }
+}
\ No newline at end of file