using MathNet.Numerics.Statistics;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OASystem.Domain.ViewModels.Groups;
using System.Collections;
using System.Globalization;
using System.Reflection;
using TinyPinyin;
namespace OASystem.Infrastructure.Tools;
/// 
/// 工具类
/// 
public static class CommonFun
{
    public static string GUID => Guid.NewGuid().ToString("N");
    public static bool IsNull(this string s)
    {
        return string.IsNullOrWhiteSpace(s);
    }
    public static bool NotNull(this string s)
    {
        return !string.IsNullOrWhiteSpace(s);
    }
    public static int GetRandom(int minNum, int maxNum)
    {
        var seed = BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0);
        return new Random(seed).Next(minNum, maxNum);
    }
    public static string GetSerialNumber(string prefix = "")
    {
        return prefix + DateTime.Now.ToString("yyyyMMddHHmmssfff") + GetRandom(1000, 9999).ToString();
    }
    public static string ToJson(this object obj)
    {
        return System.Text.Json.JsonSerializer.Serialize(obj);
    }
    public static T ToObject(this string json)
    {
        return System.Text.Json.JsonSerializer.Deserialize(json);
    }
    public static object GetDefaultVal(string typename)
    {
        return typename switch
        {
            "Boolean" => false,
            "DateTime" => default(DateTime),
            "Date" => default(DateTime),
            "Double" => 0.0,
            "Single" => 0f,
            "Int32" => 0,
            "String" => string.Empty,
            "Decimal" => 0m,
            _ => null,
        };
    }
    public static void CoverNull(T model) where T : class
    {
        if (model == null)
        {
            return;
        }
        var typeFromHandle = typeof(T);
        var properties = typeFromHandle.GetProperties();
        var array = properties;
        for (var i = 0; i < array.Length; i++)
        {
            var propertyInfo = array[i];
            if (propertyInfo.GetValue(model, null) == null)
            {
                propertyInfo.SetValue(model, GetDefaultVal(propertyInfo.PropertyType.Name), null);
            }
        }
    }
    public static void CoverNull(List models) where T : class
    {
        if (models.Count == 0)
        {
            return;
        }
        foreach (var model in models)
        {
            CoverNull(model);
        }
    }
    public static bool ToBool(this object thisValue, bool errorvalue = false)
    {
        if (thisValue != null && thisValue != DBNull.Value && bool.TryParse(thisValue.ToString(), out bool reval))
        {
            return reval;
        }
        return errorvalue;
    }
    #region 文件操作
    public static FileInfo[] GetFiles(string directoryPath)
    {
        if (!IsExistDirectory(directoryPath))
        {
            throw new DirectoryNotFoundException();
        }
        var root = new DirectoryInfo(directoryPath);
        return root.GetFiles();
    }
    public static bool IsExistDirectory(string directoryPath)
    {
        return Directory.Exists(directoryPath);
    }
    public static string ReadFile(string Path)
    {
        string s;
        if (!File.Exists(Path))
            s = "不存在相应的目录";
        else
        {
            var f2 = new StreamReader(Path, Encoding.Default);
            s = f2.ReadToEnd();
            f2.Close();
            f2.Dispose();
        }
        return s;
    }
    public static void FileMove(string OrignFile, string NewFile)
    {
        File.Move(OrignFile, NewFile);
    }
    public static void CreateDir(string dir)
    {
        if (dir.Length == 0) return;
        if (!Directory.Exists(dir))
            Directory.CreateDirectory(dir);
    }
    /// 
    /// 生成唯一存储文件名
    /// 
    ///  文件原始名称 
    /// 
    public static string GenerateStoredFileName(string originalFileName)
    {
        var extension = Path.GetExtension(originalFileName);
        var fileNameWithoutExt = Path.GetFileNameWithoutExtension(originalFileName);
        var timestamp = DateTime.Now.ToString("yyyyMMddHHmmss");
        var randomStr = Guid.NewGuid().ToString("N").Substring(0, 8);
        // 清理文件名中的非法字符
        var safeFileName = Regex.Replace(fileNameWithoutExt, @"[^\w\.-]", "");
        return $"{safeFileName}_{timestamp}_{randomStr}{extension}";
    }
    /// 
    /// 验证文件名称
    /// 
    /// 
    /// 
    public static string ValidFileName(string fileName)
    {
        if (string.IsNullOrEmpty(fileName)) return Guid.NewGuid().ToString();
        // 获取非法文件名字符
        char[] invalidChars = Path.GetInvalidFileNameChars();
        return new string(fileName.Where(c => !invalidChars.Contains(c)).ToArray());
    }
    /// 
    /// 文件后缀名签名
    /// 
    public static Dictionary> FileSignature => new Dictionary>
        {
            { ".jpeg", new List
                {
                    new byte[] { 0xFF, 0xD8, 0xFF, 0xE0 },
                    new byte[] { 0xFF, 0xD8, 0xFF, 0xE2 },
                    new byte[] { 0xFF, 0xD8, 0xFF, 0xE3 },
                }
            },
            { ".png", new List
                {
                    new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }
                }
            },
            { ".pdf", new List
                {
                    new byte[] { 0x25, 0x50, 0x44, 0x46 }
                }
            },
            { ".xls", new List
                { 
                    new byte[] { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 } 
                } 
            },
            { ".xlsx", new List 
                { 
                    new byte[] { 0x50, 0x4B, 0x03, 0x04 } 
                } 
            }
        };
    #endregion
    #region IP
    /// 
    /// 是否为ip
    /// 
    /// 
    /// 
    public static bool IsIP(string ip)
    {
        return Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$");
    }
    public static string GetIP(HttpRequest request)
    {
        if (request == null) return "";
        var ip = request.Headers["X-Real-IP"].FirstOrDefault();
        if (ip.IsNull())
        {
            ip = request.Headers["X-Forwarded-For"].FirstOrDefault();
        }
        if (ip.IsNull())
        {
            ip = request.HttpContext?.Connection?.RemoteIpAddress?.ToString();
        }
        if (ip.IsNull() || !IsIP(ip))
        {
            ip = "127.0.0.1";
        }
        return ip;
    }
    /// 
    /// IP地址获取方法(serilog 单独处理)
    /// 
    /// 
    /// 
    public static string GetClientIpAddress(HttpContext httpContext)
    {
        // 1. 尝试从X-Forwarded-For获取(处理代理/负载均衡情况)
        if (httpContext.Request.Headers.TryGetValue("X-Forwarded-For", out var forwardedFor))
        {
            // X-Forwarded-For可能包含逗号分隔的IP列表(客户端,代理1,代理2,...)
            var ip = forwardedFor.FirstOrDefault()?.Split(',').FirstOrDefault()?.Trim();
            if (!string.IsNullOrEmpty(ip))
                return ip;
        }
        // 2. 尝试从X-Real-IP获取
        if (httpContext.Request.Headers.TryGetValue("X-Real-IP", out var realIp))
        {
            var ip = realIp.FirstOrDefault();
            if (!string.IsNullOrEmpty(ip))
                return ip;
        }
        // 3. 使用连接远程IP地址
        var remoteIp = httpContext.Connection.RemoteIpAddress;
        // 处理IPv6映射的IPv4地址
        if (remoteIp != null && remoteIp.IsIPv4MappedToIPv6)
        {
            remoteIp = remoteIp.MapToIPv4();
        }
        return remoteIp?.ToString() ?? "unknown";
    }
    #endregion
    #region UserAgent
    /// 
    /// 分层检测策略实现操作系统识别
    /// 
    /// 
    /// 
    public static string DetectOS(string userAgent)
    {
        if (string.IsNullOrEmpty(userAgent)) return "Unknown";
        // 移动端优先检测
        if (IsMobile(userAgent))
        {
            if (userAgent.Contains("iPhone")) return ParseIOSVersion(userAgent);
            if (userAgent.Contains("Android")) return ParseAndroidVersion(userAgent);
            if (userAgent.Contains("Windows Phone")) return "Windows Mobile";
        }
        // PC端检测
        if (userAgent.Contains("Windows NT")) return ParseWindowsVersion(userAgent);
        if (userAgent.Contains("Macintosh")) return "macOS";
        if (userAgent.Contains("Linux")) return "Linux";
        return "Other";
    }
    /// 
    /// 移动设备判断
    /// 
    /// 
    /// 
    private static bool IsMobile(string userAgent)
    {
        string[] mobileKeywords = { "iPhone", "Android", "Windows Phone", "iPad", "iPod" };
        return mobileKeywords.Any(key => userAgent.Contains(key));
    }
    /// 
    /// iOS版本解析
    /// 
    /// 
    /// 
    private static string ParseIOSVersion(string userAgent)
    {
        var match = Regex.Match(userAgent, @"iPhone OS (\d+_\d+)");
        return match.Success ? $"iOS {match.Groups[1].Value.Replace('_', '.')}" : "iOS";
    }
    /// 
    ///  Android版本解析
    /// 
    /// 
    /// 
    private static string ParseAndroidVersion(string userAgent)
    {
        var match = Regex.Match(userAgent, @"Android (\d+)");
        return match.Success ? $"Android {match.Groups[1].Value}" : "Android";
    }
    /// 
    /// Windows版本解析
    /// 
    /// 
    /// 
    private static string ParseWindowsVersion(string userAgent)
    {
        if (userAgent.Contains("Windows NT 10.0")) return "Windows 10/11";
        if (userAgent.Contains("Windows NT 6.3")) return "Windows 8.1";
        if (userAgent.Contains("Windows NT 6.2")) return "Windows 8";
        return "Windows";
    }
    #endregion
    #region 随机数
    /// 
    /// 根据自定义随机包含的字符获取指定长度的随机字符
    /// 
    /// 随机字符长度
    /// 随机字符
    public static string GetRandomStr(int length)
    {
        string a = "ABCDEFGHJKLMNPQRSTUVWXYZ012356789";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++)
        {
            sb.Append(a[new Random(Guid.NewGuid().GetHashCode()).Next(0, a.Length - 1)]);
        }
        return sb.ToString();
    }
    /// 
    /// 根据自定义随机包含的字符获取指定长度的随机字符
    /// 
    /// 随机字符长度
    /// 随机字符
    public static string GetRandomAllStr(int length)
    {
        string a = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjklmnpqrstuvwxyz012356789";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++)
        {
            sb.Append(a[new Random(Guid.NewGuid().GetHashCode()).Next(0, a.Length - 1)]);
        }
        return sb.ToString();
    }
    /// 
    /// 根据自定义随机包含的字符获取指定长度的随机字母(含大小写)
    /// 
    /// 随机字符长度
    /// 随机字符
    public static string GetRandomLetter(int length)
    {
        string a = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjklmnpqrstuvwxyz";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++)
        {
            sb.Append(a[new Random(Guid.NewGuid().GetHashCode()).Next(0, a.Length - 1)]);
        }
        return sb.ToString();
    }
    /// 
    /// 生成不重复随机数字
    /// 操作者:037
    /// 2021-07-26 15:39
    /// 
    /// 输入字符串长度
    /// 字符串
    public static string GetRandomNumber(int len)
    {
        string allChar = "0,1,2,3,4,5,6,7,8,9";
        string[] allCharArray = allChar.Split(',');
        string RandomCode = "";
        int temp = -1;
        Random rand = new Random();
        for (int i = 0; i < len; i++)
        {
            if (temp != -1)
            {
                rand = new Random(temp * i * ((int)DateTime.Now.Ticks));
            }
            int t = rand.Next(allCharArray.Length - 1);
            while (temp == t)
            {
                t = rand.Next(allCharArray.Length - 1);
            }
            temp = t;
            RandomCode += allCharArray[t];
        }
        return RandomCode;
    }
    #endregion
    #region decimal 截取
    /// 
    /// 
    /// 
    /// 
    /// 
    /// 
    public static decimal CutDecimalWithN(decimal d, int n)
    {
        string strDecimal = d.ToString();
        int index = strDecimal.IndexOf(".");
        if (index == -1 || strDecimal.Length < index + n + 1)
        {
            strDecimal = string.Format("{0:F" + n + "}", d);
        }
        else
        {
            int length = index;
            if (n != 0)
            {
                length = index + n + 1;
            }
            strDecimal = strDecimal.Substring(0, length);
        }
        return Decimal.Parse(strDecimal);
    }
    /// 
    /// decimal 保留小数,不四舍五入
    /// 
    /// 
    /// 
    /// 
    public static decimal TruncDecimals(this decimal value, int decimalPlaces)
    {
        decimal scaleFactor = (decimal)Math.Pow(10, decimalPlaces);
        var truncated = Math.Truncate(scaleFactor * value) / scaleFactor;
        // 检查是否需要补零
        if (GetDecimalDigits(value) < decimalPlaces)
        {
            string format = "0." + new string('0', decimalPlaces);
            truncated = decimal.Parse(truncated.ToString(format));
        }
        return truncated;
    }
    private static int GetDecimalDigits(decimal number)
    {
        string[] parts = number.ToString().Split('.');
        return parts.Length > 1 ? parts[1].Length : 0;
    }
    #endregion
    #region decimal 保留两位小数
    /// 
    /// decimal 保留两位小数 不四舍五入
    /// 
    /// 
    /// 
    public static decimal DecimalsKeepTwo(this decimal myDecimal)
    {
        var subDecimal = Math.Floor(myDecimal * 100) / 100;//保留两位小数,直接截取
        return subDecimal;
    }
    #endregion
    #region 团组模块 - 汇率相关存储解析
    /// 
    /// 团组模块 - 汇率相关 To List
    /// 
    /// 
    /// 
    public static List GetCurrencyChinaToList(string? rateStr)
    {
        List currencyInfos = new List();
        if (string.IsNullOrEmpty(rateStr)) return currencyInfos;
        if (rateStr.Contains("|"))
        {
            string[] currencyArr = rateStr.Split("|");
            
            foreach (string currency in currencyArr)
            {
                if (!string.IsNullOrEmpty(currency))
                {
                    string[] currency1 = currency.Split(":");
                    string[] currency2 = currency1[0].Split("(");
                    CurrencyInfo rateInfo = new CurrencyInfo()
                    {
                        CurrencyCode = currency2[1].Replace(")", "").TrimEnd(),
                        CurrencyName = currency2[0],
                        Rate = decimal.Parse(currency1[1]),
                    };
                    currencyInfos.Add(rateInfo);
                }
            }
        }
        return currencyInfos;
    }
    /// 
    /// 团组模块 - 汇率相关存储解析 To String
    /// 
    /// 
    /// 
    public static string GetCurrencyChinaToString(List? rates)
    {
        string rateStr = string.Empty;
        if (rates == null) return rateStr;
        if (rates.Count <= 0) return rateStr;
        if (rates.Count == 1)
        {
            var rate = rates[0];
            return string.Format("{0}({1}):{2}|", rate.CurrencyName, rate.CurrencyCode, rate.Rate);
        }
        foreach (CurrencyInfo rate in rates)
        {
            //存储方式: 美元(USD):6.2350|.......|墨西哥比索(MXN):1.0000
            rateStr += string.Format("{0}({1}):{2}|", rate.CurrencyName, rate.CurrencyCode, rate.Rate);
        }
        if (rateStr.Length > 0)
        {
            rateStr = rateStr.Substring(0, rateStr.Length - 1);
        }
        return rateStr;
    }
    #endregion
    #region 验证身份证号码
    /// 
    /// 正则表达式
    /// 验证身份证号码
    /// 
    /// 
    /// 
    public static bool IsValidChineseId(this string idNumber)
    {
        string pattern = @"^[1-9]\d{5}(18|19|20|21|22)?\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}(\d|[Xx])$";
        Regex regex = new Regex(pattern);
        return regex.IsMatch(idNumber);
    }
    /// 
    /// 通过身份证提取生日
    /// 
    /// 
    /// 
    public static DateTime? GetBirthDateFromIdentityCard(string identityCard)
    {
        // 身份证号码正则表达式验证,支持18位身份证号码
        if (!Regex.IsMatch(identityCard, @"^\d{17}(\d|X|x)$"))
        {
            return null;
        }
        // 获取出生日期(8位数字)
        string birthDateString = identityCard.Substring(6, 8);
        // 尝试将出生日期字符串转换为DateTime类型
        if (DateTime.TryParse(birthDateString, out DateTime birthDate))
        {
            return birthDate;
        }
        return null;
    }
    /// 
    /// 通过身份证判断性别
    /// 
    /// 
    /// 0 男1 女 -1 未设置
    /// 
    public static int GetGenderFromIdentityCard(string idNumber)
    {
        if (string.IsNullOrEmpty(idNumber) || idNumber.Length != 18)
            return -1;
        char genderChar = idNumber[16];
        return int.Parse(genderChar.ToString()) % 2 == 0 ? 1 : 0;
    }
    #endregion
    #region string格式日期格式化
    /// 
    /// string格式日期格式化
    /// 
    /// 
    /// 
    /// 格式化标准
    /// yyyy-MM-dd  yyyy/MM/dd
    /// 
    /// 
    public static string DateFormat(this string dateStr, string format)
    {
        if (!string.IsNullOrEmpty(dateStr))
        {
            if (!string.IsNullOrEmpty(format))
            {
                DateTime result;
                if (DateTime.TryParse(dateStr, out result))
                {
                    return result.ToString(format);
                }
            }
        }
        return "";
    }
    #endregion
    /// 
    /// List to DataTable
    /// 集合转换成datatable
    /// 
    /// 
    /// 
    /// 
    public static DataTable GetDataTableFromIList(List aIList)
    {
        DataTable _returnTable = new DataTable();
        if (aIList != null && aIList.Count > 0)
        {
            object _baseObj = aIList[0];
            Type objectType = _baseObj.GetType();
            PropertyInfo[] properties = objectType.GetProperties();
            DataColumn _col;
            foreach (PropertyInfo property in properties)
            {
                _col = new DataColumn();
                _col.ColumnName = (string)property.Name;
                _col.DataType = property.PropertyType;
                _returnTable.Columns.Add(_col);
            }
            //Adds the rows to the table
            DataRow _row;
            foreach (object objItem in aIList)
            {
                _row = _returnTable.NewRow();
                foreach (PropertyInfo property in properties)
                {
                    _row[property.Name] = property.GetValue(objItem, null);
                }
                _returnTable.Rows.Add(_row);
            }
        }
        return _returnTable;
    }
    /// 
    /// List to DataTable
    /// 集合转换成datatable
    /// 
    public static DataTable ToDataTableArray(IList list)
    {
        DataTable result = new DataTable();
        if (list.Count > 0)
        {
            PropertyInfo[] propertys = list[0].GetType().GetProperties();
            foreach (PropertyInfo pi in propertys)
            {
                try
                {
                    result.Columns.Add(pi.Name, pi.PropertyType);
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"{pi.Name}:{ex.Message}");
                }
            }
            for (int i = 0; i < list.Count; i++)
            {
                ArrayList tempList = new ArrayList();
                foreach (PropertyInfo pi in propertys)
                {
                    object obj = pi.GetValue(list[i], null);
                    tempList.Add(obj);
                }
                object?[] array = tempList.ToArray();
                result.LoadDataRow(array, true);
            }
        }
        return result;
    }
    /// 
    ///获取指定月份起止日期
    /// 
    /// 
    /// 
    /// 
    public static (DateTime StartDate, DateTime EndDate) GetMonthStartAndEndDates(int year, int month)
    {
        var calendar = new GregorianCalendar();
        var daysInMonth = calendar.GetDaysInMonth(year, month);
        var startDate = new DateTime(year, month, 1);
        var endDate = new DateTime(year, month, daysInMonth);
        return (startDate, endDate);
    }
    /// 
    /// 验证json字符串是否合法
    /// 
    /// 
    /// 
    public static bool IsValidJson(string jsonString)
    {
        try
        {
            JToken.Parse(jsonString);
            return true;
        }
        catch (JsonReaderException)
        {
            return false;
        }
    }
    /// 
    /// 常见的双字姓氏列表
    /// 
    private static readonly HashSet commonDoubleSurnames = new HashSet
    {
        "欧阳", "司马", "上官", "夏侯", "诸葛", "东方", "赫连", "皇甫", "尉迟", "公羊",
        "澹台", "公冶", "宗政", "濮阳", "淳于", "单于", "太叔", "申屠", "公孙", "仲孙",
        "轩辕", "令狐", "钟离", "宇文", "长孙", "慕容", "鲜于", "闾丘", "司徒", "司空",
        "亓官", "司寇", "仉督", "子车", "颛孙", "端木", "巫马", "公西", "漆雕", "乐正",
        "壤驷", "公良", "拓跋", "夹谷", "宰父", "谷梁", "晋楚", "闫法", "汝鄢", "涂钦",
        "段干", "百里", "东郭", "南门", "呼延", "归海", "羊舌", "微生", "岳帅", "缑亢",
        "况后", "有琴", "梁丘", "左丘", "东门", "西门", "商牟", "佘佴", "伯赏", "南宫"
    };
    /// 
    /// 中文名字取姓氏和名字
    /// 
    /// 
    /// 姓:lastName 名:firstName
    public static (string lastName, string firstName) GetLastNameAndFirstName(string fullName)
    {
        if (string.IsNullOrEmpty(fullName) || fullName.Length < 2) return ("", "");
        // 尝试匹配双字姓氏
        if (fullName.Length > 2)
        {
            string potentialDoubleSurname = fullName.Substring(0, 2);
            if (commonDoubleSurnames.Contains(potentialDoubleSurname))
            {
                string lastName = potentialDoubleSurname;
                string firstName = fullName.Substring(2);
                return (lastName, firstName);
            }
        }
        // 默认单字姓氏
        string singleSurname = fullName.Substring(0, 1);
        string remainingName = fullName.Substring(1);
        return (singleSurname, remainingName);
    }
    /// 
    /// 中文名字转拼音
    /// 
    /// 
    /// 
    /// 
    public static string ConvertToPinyin(string chineseName)
    {
        if (string.IsNullOrEmpty(chineseName)) return "";
        return PinyinHelper.GetPinyin(chineseName, "").ToUpper();
    }
    #region stringBuilder 扩展
    /// 
    /// StringBuilder 验证是否有值
    /// 
    /// 
    /// 
    public static bool HasValue(this StringBuilder sb)
    {
        return sb != null && sb.Length > 0;
    }
    #endregion
    /// 
    /// 安全获取列表指定索引的值
    /// 
    public static string? GetValueOrDefault(this List list, int index)
    {
        if (list == null)
            throw new ArgumentNullException(nameof(list));
        return index >= 0 && index < list.Count ? list[index] : null;
    }
    #region 姓名 取姓和名
    /// 
    /// 取姓
    /// 
    public static string GetLastName(this string fullName)
    {
        if (string.IsNullOrWhiteSpace(fullName)) return string.Empty;
        // 1. 英文/拼音:有逗号
        var comma = fullName.IndexOf(',');
        if (comma >= 0) return fullName[..comma].Trim();
        // 2. 英文/拼音:无逗号,按最后一个空格切
        var lastSpace = fullName.LastIndexOf(' ');
        if (lastSpace >= 0) return fullName[..lastSpace].Trim();
        // 3. 中文:默认首字为姓
        return fullName.Length switch
        {
            0 => string.Empty,
            1 => fullName,
            _ => fullName[..1]   // 复姓可改成 ..2
        };
    }
    /// 
    /// 取名(去掉姓)
    /// 
    public static string GetFirstName(this string fullName)
    {
        if (string.IsNullOrWhiteSpace(fullName)) return string.Empty;
        var comma = fullName.IndexOf(',');
        if (comma >= 0) return fullName[(comma + 1)..].Trim();
        var lastSpace = fullName.LastIndexOf(' ');
        if (lastSpace >= 0) return fullName[(lastSpace + 1)..].Trim();
        // 中文:去掉首字
        return fullName.Length <= 1 ? string.Empty : fullName[1..];
    }
    #endregion
    /// 
    /// 从地址字符串取出省份和城市
    /// 
    public static (string province, string city) SplitProvinceCity(string src)
    {
        if (string.IsNullOrWhiteSpace(src)) return ("", "");
        ReadOnlySpan s = src.AsSpan();
        // 1. 省
        int pEnd = s.IndexOf("省");
        if (pEnd < 0) pEnd = s.IndexOf("自治区");
        string province = pEnd < 0 ? "" : s[..pEnd].ToString();
        // 2. 市
        int cStart = pEnd + (pEnd >= 0 ? (province.EndsWith("自治区") ? 3 : 1) : 0);
        int cEnd = s[cStart..].IndexOf("市");
        string city = cEnd < 0 ? "" : s.Slice(cStart, cEnd).ToString();
        return (province, city);
    }
}