using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Net.Mail; using System.Text; using System.Text.RegularExpressions; using XFEExtension.NetCore.XFETransform; using XFEExtension.NetCore.XFETransform.ObjectInfoAnalyzer; using XFEExtension.NetCore.XFETransform.StringConverter; namespace XFEExtension.NetCore.StringExtension; /// /// 字符串拓展类 /// public static partial class StringExtension { #region 正则表达式 [GeneratedRegex(@"^(\d{3,4}-)?\d{6,8}$")] private static partial Regex TelePhoneRegex(); [GeneratedRegex(@"^1[3456789]\d{9}$")] private static partial Regex MobPhoneNumberRegex(); [GeneratedRegex(@"^\d{6}$")] private static partial Regex PostalCodeRegex(); [GeneratedRegex(@"^[0-9]*$")] private static partial Regex NumberRegex(); [GeneratedRegex(@"(^\d{18}$)|(^\d{15}$)")] private static partial Regex IdCardRegex(); [GeneratedRegex(@"(?:https?\:\/\/|[wW]{3}\.)(?:[a-zA-Z0-9\-]+(?:\.[a-zA-Z]{2,})+|localhost)(\:[0-9]{2,})?(?:\/[^\s]*)?")] private static partial Regex UrlRegex(); #endregion /// extension(string telephoneNum) { /// /// 判断字符串是否为座机号码 /// /// public bool IsTelePhone() => TelePhoneRegex().IsMatch(telephoneNum); /// /// 判断字符串是否为手机号码 /// /// public bool IsMobPhoneNumber() => MobPhoneNumberRegex().IsMatch(telephoneNum); /// /// 判断字符串是否为邮政编码 /// /// public bool IsPostalCode() => PostalCodeRegex().IsMatch(telephoneNum); /// /// 判断字符串是否为数字 /// /// public bool IsNumber() => NumberRegex().IsMatch(telephoneNum); /// /// 判断字符串是否为身份证件号 /// /// public bool IsIdCard() => IdCardRegex().IsMatch(telephoneNum); /// /// 判断字符串是否为邮箱地址 /// /// public bool IsValidEmail() { if (string.IsNullOrWhiteSpace(telephoneNum)) return false; try { telephoneNum = Regex.Replace(telephoneNum, @"(@)(.+)$", DomainMapper, RegexOptions.None, TimeSpan.FromMilliseconds(200)); _ = new MailAddress(telephoneNum).Host; return Regex.IsMatch(telephoneNum, """^(?(")(".+?"@)|(([0-9a-zA-Z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)[0-9a-zA-Z]\@))(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,}))$""", RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250)); } catch (FormatException) { return false; } } /// /// 验证是否是URL链接 /// /// public bool IsUrl() { var pattern = @"^(https?|ftp|file|ws)://([\w-]+\.)+[\w-]+(/[\w- ./?%&=]*)?$"; return IsMatch(pattern, telephoneNum); } /// /// 字符串实际显示的长度 /// /// public int DisplayLength() { var lengthCount = 0; var splits = telephoneNum.ToCharArray(); foreach (var split in splits) { if (split == '\t') { lengthCount += 8 - lengthCount % 8; } else { if (split > 255) { lengthCount += 2; } else { lengthCount += 1; } } } return lengthCount; } } /// extension([NotNullWhen(false)] string? str) { /// /// 字符串为 null 或者是空字符串 /// public bool NullOrEmpty => string.IsNullOrEmpty(str); /// /// 字符串为 null 、空字符串或仅包含空格 /// public bool NullOrWhiteSpace => string.IsNullOrWhiteSpace(str); /// /// 判断字符串是否为 null 或者是空字符串 /// /// public bool IsNullOrEmpty() => string.IsNullOrEmpty(str); /// /// 判断字符串是否是 null 、空字符串和仅包含空格的字符串 /// /// public bool IsNullOrWhiteSpace() => string.IsNullOrWhiteSpace(str); } private static string DomainMapper(Match match) { var idn = new IdnMapping(); var domainName = match.Groups[2].Value; domainName = idn.GetAscii(domainName); return match.Groups[1].Value + domainName; } /// /// 判断一个字符串,是否匹配指定的表达式(区分大小写的情况下) /// /// 正则表达式 /// 要匹配的字符串 /// public static bool IsMatch(string expression, string str) => !string.IsNullOrEmpty(str) && new Regex(expression).IsMatch(str); /// extension(string? str) { /// /// 提取字符串中的URL链接 /// /// public string[]? GetUrl() { if (str is null) return null; var regex = UrlRegex(); var matches = regex.Matches(str); var result = new string[matches.Count]; for (var i = 0; i < matches.Count; i++) result[i] = matches[i].Value; return result; } /// /// 替换字符串中的多个字符串为指定字符串 /// /// 替换的字符串组 /// 目的字符串 /// public string? ReplaceStrings(string[] replaceStringArray, string tarString) => replaceStringArray.Aggregate(str, (current, replaceString) => current?.Replace(replaceString, tarString)); /// /// 匹配两个字符串之间的字符串 /// /// 起始字符串 /// 结束字符串 /// public string[] MatchStringsBetween(string startString, string endString) { if (str.IsNullOrWhiteSpace()) return []; var pattern = $"{Regex.Escape(startString)}(.*?){Regex.Escape(endString)}"; var matches = Regex.Matches(str, pattern); var result = new string[matches.Count]; for (var i = 0; i < matches.Count; i++) result[i] = matches[i].Groups[1].Value; return result; } /// /// 文本自动换行 /// /// 一行文本的最大长度 /// [return: NotNullIfNotNull(nameof(str))] public string? WrapText(int width) { if (str is null) return str; StringBuilder stringBuilder = new(); var startIndex = 0; while (startIndex < str.Length) { // 寻找下一个换行位置 var endIndex = startIndex + width; if (endIndex >= str.Length) { // 如果已经到达文本末尾,则直接添加剩余部分并结束循环 stringBuilder.Append(str[startIndex..]); break; } // 在指定宽度范围内寻找最后一个空格字符 var lastSpaceIndex = str.LastIndexOf(' ', endIndex, width); if (lastSpaceIndex > startIndex) { // 如果找到了空格字符,则将文本从起始位置到空格字符位置添加到结果中,并进行换行 stringBuilder.Append(str[startIndex..lastSpaceIndex]); stringBuilder.AppendLine(); startIndex = lastSpaceIndex + 1; } else { // 如果没有找到空格字符,则直接添加指定宽度的文本到结果中,并进行换行 stringBuilder.Append(str.AsSpan(startIndex, width)); stringBuilder.AppendLine(); startIndex += width; } } return stringBuilder.ToString(); } } /// extension(object obj) { /// /// 输出到控制台并返回 /// /// ToString后的内容 public string? WriteLineToConsole() { Console.WriteLine(obj); return obj.ToString(); } /// /// 输出到控制台 /// public void CW() { Console.WriteLine(obj); } } /// 待分析的对象 extension(object? obj) { /// /// 分析对象并输出到控制台 /// /// 对象别名 /// /// public string X(bool onlyProperty = true, bool onlyPublic = true, string remarkName = "分析对象") { var fatherList = new List(); if (obj is not null) fatherList.Add(obj); var result = XFEConverter.GetObjectInfo(StringConverter.ObjectAnalyzer, remarkName, ObjectPlace.Main, 0, fatherList, obj?.GetType(), obj, onlyProperty, onlyPublic).OutPutObject(); Console.WriteLine(result); return result; } /// /// 分析对象并输出到跟踪输出 /// /// 对象别名 /// /// public string XL(string remarkName = "分析对象", bool onlyProperty = true, bool onlyPublic = true) { var fatherList = new List(); if (obj is not null) fatherList.Add(obj); var result = XFEConverter.GetObjectInfo(StringConverter.ObjectAnalyzer, remarkName, ObjectPlace.Main, 0, fatherList, obj?.GetType(), obj, onlyProperty, onlyPublic).OutPutObject(); Trace.WriteLine(result); return result; } } /// /// 随机生成指定长度的字符串 /// /// 字符串的长度 /// public static string GenerateRandomString(int length) { const string allowedChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; Random random = new(); var randomChars = new char[length]; for (var i = 0; i < length; i++) { var randomIndex = random.Next(0, allowedChars.Length); randomChars[i] = allowedChars[randomIndex]; } return new string(randomChars); } /// /// 随机生成指定长度指定字符串组合的字符串 /// /// 字符串的长度 /// 允许的字符串 /// public static string GenerateRandomString(int length, string allowedChars) { Random random = new(); var randomChars = new char[length]; for (var i = 0; i < length; i++) { var randomIndex = random.Next(0, allowedChars.Length); randomChars[i] = allowedChars[randomIndex]; } return new string(randomChars); } #region 返回包含分割器的字符串 /// extension(string str) { /// /// 返回包含分割器的字符串 /// /// 分割器组 /// 是否移除空字符串 /// 分割后的带分割器字符串数组 public string[] SplitAndKeepDelimiter(string[] delimiter, bool removeEmptyString) { var result = str.Split(delimiter, removeEmptyString ? StringSplitOptions.RemoveEmptyEntries : StringSplitOptions.None); for (var i = 0; i < result.Length - 1; i++) { result[i] += delimiter; } return result; } /// /// 返回包含分割器的字符串 /// /// 分割器 /// 是否移除空字符串 /// 分割后的带分割器字符串数组 public string[] SplitAndKeepDelimiter(string delimiter, bool removeEmptyString) { return str.SplitAndKeepDelimiter([delimiter], removeEmptyString); } /// /// 返回包含分割器的字符串 /// /// 分割器 /// 分割后的带分割器字符串数组 public string[] SplitAndKeepDelimiter(string delimiter) { return str.SplitAndKeepDelimiter([delimiter], true); } /// /// 返回包含分割器的字符串 /// /// 分割器组 /// 分割后的带分割器字符串数组 public string[] SplitAndKeepDelimiter(string[] delimiter) { return str.SplitAndKeepDelimiter(delimiter, true); } } #endregion }