C#验证身份证号码:从基础格式检查到严格校验的实现方案
在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)
动作:
- 去除字符串首尾空格。
- 匹配中国大陆行政区划代码开头(11~65等)。
- 匹配剩余长度为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)
动作:
- 使用正则
^\d{17}(\d|x)$强制限定为18位。 - 将前两位转换为整数,对照
aCity数组查找非法地区。 - 截取第7-14位尝试构造日期对象,失败则提示“非法生日”。
- 使用加权因子法计算和值,验证最后一位是否为 '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
动作:
- 分流:根据长度调用对应的子函数。
- 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位字符(忽略大小写)。
重要参数: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#数据校验的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









