利用C#计算身份证校验码,身份证号码合法性验证、提取前 17 位并补全校验码

首次发布:2025-12-15

身份证上数字含义

核心代码

using System;
using System.Text.RegularExpressions;

namespace WindowsFormsApp1
{
    /// <summary>
    /// 身份证号码工具类(支持18位身份证,含校验码计算、合法性验证)
    /// </summary>
    public static class IdCardValidationHelper
    {
        #region 私有常量
        /// <summary>
        /// 前17位对应的加权因子(固定序列)
        /// </summary>
        private static readonly int[] WeightFactors = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };

        /// <summary>
        /// 余数与校验码的映射表(索引对应余数0-10)
        /// </summary>
        private static readonly char[] CheckCodeMap = { '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' };
        #endregion

        #region 公共方法
        /// <summary>
        /// 根据18位身份证号码验证其合法性(含校验码验证+格式验证)
        /// </summary>
        /// <param name="idCardNumber">18位身份证号码</param>
        /// <returns>是否合法</returns>
        public static bool IsValidIdCard(string idCardNumber)
        {
            // 1. 基础格式验证(长度18位、前17位为数字、第18位为数字或X)
            if (!IsIdCardFormatValid(idCardNumber))
            {
                return false;
            }

            // 2. 校验码验证
            return IsCheckCodeValid(idCardNumber);
        }

        /// <summary>
        /// 计算17位身份证前缀对应的校验码
        /// </summary>
        /// <param name="idCardPrefix17">17位身份证前缀(必须为数字)</param>
        /// <returns>校验码(大写X或数字)</returns>
        /// <exception cref="ArgumentException">前缀不合法时抛出异常</exception>
        public static char CalculateCheckCode(string idCardPrefix17)
        {
            // 验证17位前缀的合法性
            if (string.IsNullOrEmpty(idCardPrefix17) || idCardPrefix17.Length != 17 || !IsAllDigits(idCardPrefix17))
            {
                throw new ArgumentException("输入的身份证前缀必须是17位数字", nameof(idCardPrefix17));
            }

            // 1. 计算加权和
            int sum = 0;
            for (int i = 0; i < 17; i++)
            {
                // 将字符转换为数字(char转int需减去'0'的ASCII值)
                int digit = idCardPrefix17[i] - '0';
                sum += digit * WeightFactors[i];
            }

            // 2. 计算模11的余数
            int remainder = sum % 11;

            // 3. 映射得到校验码
            return CheckCodeMap[remainder];
        }

        /// <summary>
        /// 补全17位身份证前缀为完整的18位身份证号码
        /// </summary>
        /// <param name="idCardPrefix17">17位身份证前缀</param>
        /// <returns>18位身份证号码</returns>
        /// <exception cref="ArgumentException">前缀不合法时抛出异常</exception>
        public static string CompleteIdCardNumber(string idCardPrefix17)
        {
            char checkCode = CalculateCheckCode(idCardPrefix17);
            return idCardPrefix17 + checkCode;
        }
        #endregion

        #region 私有辅助方法
        /// <summary>
        /// 验证身份证号码的格式是否合法(18位、前17位数字、第18位数字或X)
        /// </summary>
        /// <param name="idCardNumber">身份证号码</param>
        /// <returns>格式是否合法</returns>
        private static bool IsIdCardFormatValid(string idCardNumber)
        {
            if (string.IsNullOrEmpty(idCardNumber) || idCardNumber.Length != 18)
            {
                return false;
            }

            // 正则匹配:前17位为数字,第18位为数字或大写X
            string pattern = @"^\d{17}[\dX]$";
            return Regex.IsMatch(idCardNumber, pattern);
        }

        /// <summary>
        /// 验证身份证号码的校验码是否正确
        /// </summary>
        /// <param name="idCardNumber">18位身份证号码</param>
        /// <returns>校验码是否正确</returns>
        private static bool IsCheckCodeValid(string idCardNumber)
        {
            // 提取前17位
            string prefix17 = idCardNumber.Substring(0, 17);
            // 计算应有的校验码
            char expectedCheckCode = CalculateCheckCode(prefix17);
            // 提取实际的第18位(统一转为大写,兼容小写x)
            char actualCheckCode = char.ToUpper(idCardNumber[17]);

            return expectedCheckCode == actualCheckCode;
        }

        /// <summary>
        /// 判断字符串是否全部为数字
        /// </summary>
        /// <param name="input">输入字符串</param>
        /// <returns>是否全部为数字</returns>
        private static bool IsAllDigits(string input)
        {
            foreach (char c in input)
            {
                if (!char.IsDigit(c))
                {
                    return false;
                }
            }
            return true;
        }
        #endregion
    }
}

使用示例

// 示例1:计算17位前缀的校验码
string prefix17 = "21041419010306091";
char checkCode = IdCardValidationHelper.CalculateCheckCode(prefix17);
MessageBox.Show($"17位前缀【{prefix17}】的校验码是:{checkCode}");

// 示例2:补全为18位身份证号码
string fullIdCard = IdCardValidationHelper.CompleteIdCardNumber(prefix17);
MessageBox.Show($"完整的身份证号码:{fullIdCard}");

// 示例3:验证身份证号码的合法性
string testIdCard = "210414190103060911"; // 合法号码
bool isValid = IdCardValidationHelper.IsValidIdCard(testIdCard);
MessageBox.Show($"身份证号码【{testIdCard}】是否合法:{isValid}");

string invalidIdCard = "210414190103060916"; // 非法号码(校验码错误)
bool isInvalid = IdCardValidationHelper.IsValidIdCard(invalidIdCard);
MessageBox.Show($"身份证号码【{invalidIdCard}】是否合法:{isInvalid}");

本文来自 www.luofenming.com