C#验证身份证号码:从基础格式检查到严格校验的实现方案

Felix
Felix
发布时间:2026-10-13 | 3人浏览过
原创

在C#开发中,验证身份证号码通常需要处理15位旧证和18位新证两种格式。本文整理了三种不同层级的验证方法:基础的正则表达式匹配、结合日期与地区信息的复杂校验,以及完全符合国家标准GB11643-1999的严谨算法实现。

结果与目标

用户需要一个可靠的工具类或函数,能够准确识别输入字符串是否为合法的身份证号码,并区分无效类型(如非法地区、生日错误或校验码不符)。

准备条件

  • 环境要求:.NET Framework 或 .NET Core/5+ 环境。
  • 依赖库:主要使用 System.Text.RegularExpressions 进行正则处理,System.DateTime 进行日期验证,以及 System.Linq 辅助计算。
  • 核心逻辑:需理解身份证前6位为地址码,中间8位(或6位)为生日码,最后1位为校验码的计算规则。

真实操作顺序

第1步:基础格式与区域预检(快速过滤)

目的:通过正则表达式快速排除明显不合规的长度和非数字字符,适用于对性能要求极高且不需要深入校验的场景。

入口:IsIdCard(string idCard)

动作:

  1. 去除字符串首尾空格。
  2. 匹配中国大陆行政区划代码开头(11~65等)。
  3. 匹配剩余长度为13位数字(15位证的后半段)或13位数字加X/d(18位证的后半段)。

重要参数:pattern 定义了严格的正则串。

完成状态:return true 仅表示格式“看起来”正确,未验证生日有效性及最后一位校验码。

public static bool IsIdCard(string idCard)
{
    if (string.IsNullOrWhiteSpace(idCard))
        return true;

    // 清除要验证字符串中的空格
    idCard = idCard.Trim();

    // 模式字符串:以有效省级代码开头,后接13个数字或13个数字+校验位
    StringBuilder pattern = new StringBuilder();
    pattern.Append(@"^(11|12|13|14|15|21|22|23|31|32|33|34|35|36|37|41|42|43|44|45|46|");
    pattern.Append(@"50|51|52|53|54|61|62|63|64|65|71|81|82|91)");
    pattern.Append(@"(\d{13}|\d{15}[\dx])$");

    // 验证
    return Regex.IsMatch(idCard, pattern.ToString());
}

第2步:复杂逻辑校验(地区+日期+简易验码)

目的:增加对出生日期的合理性判断(通过TryParse)以及简单的奇偶性性别判断,能返回更详细的错误信息。

入口:CheckCidInfo(string cid)

动作:

  1. 使用正则 ^\d{17}(\d|x)$ 强制限定为18位。
  2. 将前两位转换为整数,对照 aCity 数组查找非法地区。
  3. 截取第7-14位尝试构造日期对象,失败则提示“非法生日”。
  4. 使用加权因子法计算和值,验证最后一位是否为 '1'(对应校验码位置),这里逻辑较为简化,实际生产建议采用第3步标准。

注意:此版本中的校验码算法存在简略,主要用于演示流程,不建议直接用于金融级业务。

private string CheckCidInfo(string cid)
{
    // 基础18位正则验证
    System.Text.RegularExpressions.Regex rg = new System.Text.RegularExpressions.Regex(@"^\d{17}(\d|x|X)$");
    System.Text.RegularExpressions.Match mc = rg.Match(cid);
    if (!mc.Success) return "";

    // 地区映射表
    string[] aCity = new string[]{
        null,null,null,null,null,null,null,null,null,null,null,
        "北京","天津","河北","山西","内蒙古",null,null,null,null,null,
        "辽宁","吉林","黑龙江",null,null,null,null,null,null,null,
        "上海","江苏","浙江","安徽","福建","江西","山东",null,null,null,
        "河南","湖北","湖南","广东","广西","海南",null,null,null,
        "重庆","四川","贵州","云南","西藏",null,null,null,null,null,null,
        "陕西","甘肃","青海","宁夏","新疆",null,null,null,null,null,
        "台湾",null,null,null,null,null,null,null,null,null,
        "香港","澳门",null,null,null,null,null,null,null,null,"国外"
    };

    try
    {
        // 地区检查
        int areaCode = int.Parse(cid.Substring(0, 2));
        if (areaCode > 65 || aCity[areaCode] == null) return "非法地区";

        // 生日检查
        string birthStr = $"{cid.Substring(6,4)}-{cid.Substring(10,2)}-{cid.Substring(12,2)}";
        DateTime.Parse(birthStr); // 若格式错误或日期无效会抛出异常
    }
    catch
    {
        return "非法生日";
    }

    // 此处省略复杂的加权求和校验细节,返回格式化的地区-生日-性别信息
    return $"地区: {aCity[int.Parse(cid.Substring(0, 2))]}; 生日: {cid.Substring(6, 4)}-{cid.Substring(10, 2)}-{cid.Substring(12, 2)}";
}

第3步:标准GB11643-1999严格校验(推荐)

目的:完全符合国家标准,支持15位升18位的逻辑检查,准确验证17位加权值和第18位校验码(包括X)。

入口:CheckIDCard(string Id) -> 分发至 CheckIDCard18 或 CheckIDCard15

动作:

  1. 分流:根据长度调用对应的子函数。
  2. 18位校验逻辑:
  • 数字验证:前17位必须为数字。
  • 省份验证:前2位必须在标准省份代码列表中(使用字符串索引查询优化)。
  • 日期验证:提取第7-14位,插入 '-' 形成 YYYY-MM-DD 格式,尝试 DateTime.TryParse。
  • 校验码验证:这是核心步骤。
    • 定义加权因子数组 Wi: [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]。
    • 定义校验码对应数组 arrVarifyCode: ["1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"]。
    • 遍历前17位,每位数值乘以对应位置的 Wi,累加得到 Sum。
    • 计算 Y = Sum % 11。
    • 比较 arrVarifyCode[Y] 是否等于第18位字符(忽略大小写)。
  • 15位校验逻辑:主要验证全数字、省份代码及出生日期合法性。由于15位证无校验码字段,通常只做结构合法校验。
  • 重要参数:Wi 数组权重不可篡改,arrVarifyCode 顺序必须固定。

    可观察的完成状态:所有验证通过后返回 true,任意一步失败返回 false。

    /// <summary>
    /// 身份证验证入口
    /// </summary>
    public bool CheckIDCard(string Id)
    {
        if (Id.Length == 18)
            return CheckIDCard18(Id);
        else if (Id.Length == 15)
            return CheckIDCard15(Id);
        else
            return false;
    }
    
    /// <summary>
    /// 18位身份证验证 (GB11643-1999标准)
    /// </summary>
    private bool CheckIDCard18(string Id)
    {
        // 1. 数字验证:前17位必须是数字
        long n = 0;
        if (long.TryParse(Id.Remove(17), out n) == false || 
            n < Math.Pow(10, 16))
        {
            return false; 
        }
    
        // 2. 省份验证:检查前两位是否在合法列表
        // 使用x分隔符快速构建查找串
        string address = "11x22x35x44x53x12x23x36x45x54x13x31x37x46x61x14x32x41x50x62x15x33x42x51x63x21x34x43x52x64x65x71x81x82x91";
        if (address.IndexOf(Id.Remove(2)) == -1)
        {
            return false;
        }
    
        // 3. 生日验证:YYYYMMDD -> YYYY-MM-DD
        string birth = Id.Substring(6, 8).Insert(6, "-").Insert(4, "-");
        DateTime time = new DateTime();
        if (DateTime.TryParse(birth, out time) == false)
        {
            return false;
        }
    
        // 4. 校验码验证
        string[] arrVarifyCode = new string[]{"1", "0", "x", "9", "8", "7", "6", "5", "4", "3", "2"};
        int[] Wi = new int[]{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
        char[] Ai = Id.Remove(17).ToCharArray();
    
        int sum = 0;
        for (int i = 0; i < 17; i++)
        {
            sum += Wi[i] * int.Parse(Ai[i].ToString());
        }
    
        int y = -1;
        Math.DivRem(sum, 11, out y);
        
        // 最后一位需与计算出的校验码一致(忽略大小写)
        if (arrVarifyCode[y] != Id.Substring(17, 1).ToLower())
        {
            return false;
        }
    
        return true;
    }
    
    /// <summary>
    /// 15位身份证验证
    /// </summary>
    private bool CheckIDCard15(string Id)
    {
        long n = 0;
        // 数字验证
        if (long.TryParse(Id, out n) == false || n < Math.Pow(10, 14))
        {
            return false;
        }
    
        // 省份验证
        string address = "11x22x35x44x53x12x23x36x45x54x13x31x37x46x61x14x32x41x50x62x15x33x42x51x63x21x34x43x52x64x65x71x81x82x91";
        if (address.IndexOf(Id.Remove(2)) == -1)
        {
            return false;
        }
    
        // 生日验证
        string birth = Id.Substring(6, 6).Insert(4, "-").Insert(2, "-");
        DateTime time = new DateTime();
        if (DateTime.TryParse(birth, out time) == false)
        {
            return false;
        }
    
        return true;
    }

    简要总结

    上述内容涵盖了从轻量级正则匹配到严格国标算法的C#身份证验证实现。对于大多数业务场景,推荐使用 CheckIDCard18 中的标准算法,因为它不仅检查了结构和地区,还通过加权模11算法确保了数据的完整性,能有效防止录入错误。以上就是C#验证身份证详细功能的详细内容,更多关于C#数据校验的资料请关注本站其它相关文章!

    本站声明

    本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

    Python 相关产品和应用

    全部下载

    专题列表