You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在C#中高效校验16位卡号是否匹配预定义前缀范围的实现方案

在C#中高效校验16位卡号是否匹配预定义前缀范围的实现方案

兄弟,你原来的思路确实踩了个大坑——像那个16位的前缀范围,要生成几百万甚至上千万个字符串存进HashSet,分分钟就内存溢出了!咱们得换个聪明的办法:不用生成所有前缀,直接对卡号的对应长度前缀做数值范围判断,既省内存又高效。

核心思路

每个前缀范围其实都隐含了两个关键信息:前缀的长度,以及该长度下的数值区间。比如945-965就是要求卡号的前3位落在945到965之间,6337461000000000-6337468549999999就是要求整个16位卡号落在这个区间里。

所以我们只需要:

  1. 提前解析所有前缀范围,记录每个范围的最小值、最大值和前缀长度
  2. 校验卡号时,遍历每个范围,提取卡号对应长度的前缀,转成数值后判断是否在该范围的区间内
  3. 只要有一个范围匹配,就返回true

具体代码实现

首先我们定义一个简单的类来存储每个前缀范围的信息:

private class PrefixRange
{
    public long Min { get; set; }
    public long Max { get; set; }
    public int Length { get; set; }
}

然后替换原来的字段和方法,改成高效的版本:

private string _ranges = "11220, 11221; 6337461000000000, 6337468549999999; 945, 965;";
private List<PrefixRange> _prefixRanges;
private readonly object _rangeLock = new object();

// 初始化前缀范围(只执行一次)
private void InitializePrefixRanges()
{
    if (_prefixRanges != null) return;
    if (string.IsNullOrWhiteSpace(_ranges))
    {
        _prefixRanges = new List<PrefixRange>();
        return;
    }

    lock (_rangeLock)
    {
        // 双重检查锁,确保线程安全且只初始化一次
        if (_prefixRanges != null) return;

        var rangesList = new List<PrefixRange>();
        // 拆分每个范围组,忽略空项
        var rangeParts = _ranges.Split(';', StringSplitOptions.RemoveEmptyEntries);

        foreach (var rangeStr in rangeParts)
        {
            // 拆分最小值和最大值
            var minMaxParts = rangeStr.Split(',', StringSplitOptions.RemoveEmptyEntries);
            if (minMaxParts.Length != 2) continue;

            // 尝试解析数值,避免非法输入
            if (long.TryParse(minMaxParts[0].Trim(), out var min) 
                && long.TryParse(minMaxParts[1].Trim(), out var max))
            {
                var prefixLength = minMaxParts[0].Trim().Length;
                // 确保最小值和最大值的前缀长度一致(避免比如123-1234这种不合法的范围)
                if (max.ToString().Length != prefixLength) continue;
                
                rangesList.Add(new PrefixRange 
                { 
                    Min = min, 
                    Max = max, 
                    Length = prefixLength 
                });
            }
        }

        _prefixRanges = rangesList;
    }
}

// 卡号校验方法
public bool IsCardNumberValid(string cardNumber)
{
    // 先校验卡号格式是否符合要求
    if (string.IsNullOrWhiteSpace(cardNumber) || cardNumber.Length != 16)
    {
        return false;
    }

    // 初始化前缀范围(只执行一次)
    InitializePrefixRanges();
    if (_prefixRanges.Count == 0) return false;

    foreach (var range in _prefixRanges)
    {
        // 如果卡号长度小于当前前缀长度,直接跳过(不可能匹配)
        if (cardNumber.Length < range.Length) continue;

        // 提取对应长度的前缀
        var prefixStr = cardNumber.Substring(0, range.Length);
        // 转成数值(卡号是纯数字,这里大概率不会失败)
        if (!long.TryParse(prefixStr, out var prefixValue)) continue;

        // 判断是否在范围内,匹配到就直接返回true
        if (prefixValue >= range.Min && prefixValue <= range.Max)
        {
            return true;
        }
    }

    // 所有范围都不匹配
    return false;
}

方案优势

  • 内存占用极低:不管范围多大,只存储每个范围的三个数值,完全不会出现内存溢出的问题
  • 校验效率高:时间复杂度是O(n),n是前缀范围的数量,遍历速度极快
  • 线程安全:用双重检查锁确保初始化过程的线程安全
  • 容错性强:自动跳过非法的范围输入,避免程序崩溃

注意事项

  • 确保输入的前缀范围是合法的:最小值≤最大值,且最小值和最大值的长度一致(比如不能出现123-1234这种长度不一致的范围)
  • 卡号必须是16位纯数字字符串,如果有非数字字符,对应的范围判断会自动跳过
  • 如果需要支持更长的卡号(超过16位),可以把long换成decimal或者BigInteger,避免数值溢出

备注:内容来源于stack exchange,提问作者Bhav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 13:12:44