身分證字號結構 (GB 11643-1999)
- 地址碼 (1-6 位):省(2) + 市(2) + 區/縣(2)
- 出生日期 (7-14 位):YYYYMMDD
- 順序碼 (15-17 位):奇數=男、偶數=女
- 校驗碼 (第 18 位):0-9 或 X (代表 10)
完整驗證代碼
public static class IdCardValidator
{
// 行政區劃代碼表 (部分)
private static readonly string[] AreaCodes = {
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, "國外"
};
// 加權因子
private static readonly int[] Weights = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
// 校驗碼對應表 (索引 = 模 11 餘數)
private static readonly char[] CheckCodes = { '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' };
public static (bool Valid, string Info) Validate(string idCard)
{
if (string.IsNullOrWhiteSpace(idCard)) return (false, "空白");
idCard = idCard.Trim().ToUpper();
// 1. 格式正則: 17 位數字 + 1 位數字或 X
if (!Regex.IsMatch(idCard, @"^\d{17}[\dX]$"))
return (false, "格式錯誤");
// 2. 地址碼檢查
int area = int.Parse(idCard.Substring(0, 2));
if (area >= AreaCodes.Length || AreaCodes[area] == null)
return (false, "非法地區代碼");
// 3. 生日檢查
if (!DateTime.TryParseExact(idCard.Substring(6, 8), "yyyyMMdd", null, DateTimeStyles.None, out _))
return (false, "非法生日");
// 4. 校驗碼計算
int sum = 0;
for (int i = 0; i < 17; i++)
{
sum += (idCard[i] - '0') * Weights[i];
}
char expectedCheck = CheckCodes[sum % 11];
char actualCheck = idCard[17];
if (expectedCheck != actualCheck)
return (false, "校驗碼錯誤");
// 5. 解析資訊
string gender = (int.Parse(idCard.Substring(16, 1)) % 2 == 1) ? "男" : "女";
string birthday = $"{idCard.Substring(6, 4)}-{idCard.Substring(10, 2)}-{idCard.Substring(12, 2)}";
string info = $"{AreaCodes[area]},{birthday},{gender}";
return (true, info);
}
}
使用範例
var (valid, info) = IdCardValidator.Validate("11010519900307853X");
if (valid) Console.WriteLine($"有效: {info}"); // 有效: 北京,1990-03-07,男
else Console.WriteLine($"無效: {info}");
關鍵點說明
- 正則預檢:快速過濾長度、字元非法情況。
- 地址碼表:需根據最新行政區劃更新 (可載入外部資源檔)。
- 日期驗證:使用
DateTime.TryParseExact 自動處理閏年、月份天數。
- 校驗算法:
Σ(位值 × 權重) mod 11 查表對應。
- 效能:無複雜運算,適合高頻呼叫。