身份证检验算法

18身份证号码的结构
  公民身份号码是特征组合码,由十七位数字本体码和一位校验码组成。

  排列顺序从左至右依次为:六位数字地址码,八位数字出生日期码,三位数字顺序码和一位校验码。 
1、地址码 
  
表示编码对象常住户口所在县(市、旗、区)的行政区域划分代码,按GB/T2260的规定执行。
2、出生日期码 
  表示编码对象出生的年、月、日,按GB/T7408的规定执行,年、月、日代码之间不用分隔符。 
3、顺序码 
  
表示在同一地址码所标识的区域范围内,对同年、同月、同日出生的人编定的顺序号,顺序码的奇数分配给男性,偶数分配给女性 
4、校验码计算步骤

(1)十七位数字本体码加权求和公式 
  S = Sum(Ai * Wi), i = 0, ... , 16 ,先对前17位数字的权求和 
  Ai:表示第i位置上的身份证号码数字值(0~9) 
  Wi:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 (表示第i位置上的加权因子)
(2)计算模 
  
Y = mod(S, 11)

(3)根据模,查找得到对应的校验码 
  
Y: 0 1 2 3 4 5 6 7 8 9 10 
  校验码: 1 0 X 9 8 7 6 5 4 3 2

例子:

  1 using System;
  2 using System.Collections.Generic;
  3 using System.ComponentModel;
  4 using System.Data;
  5 using System.Drawing;
  6 using System.Linq;
  7 using System.Text;
  8 using System.Threading.Tasks;
  9 using System.Windows.Forms;
 10 
 11 namespace TestForm
 12 {
 13     public partial class Form1 : Form
 14     {
 15         public Form1()
 16         {
 17             InitializeComponent();
 18         }
 19 
 20         private void txtId_KeyPress(object sender, KeyPressEventArgs e)
 21         {
 22             if (e.KeyChar < '0' || e.KeyChar > '9')
 23             {
 24                 //输入数字以为的字符就阻止掉
 25                 e.Handled = true;
 26             }
 27             //如果第18位输入的是x,则不阻止
 28             if ((txtId.SelectionStart == 17) && (e.KeyChar == 'x' || e.KeyChar == 'X'))
 29             {
 30                 e.Handled = false;
 31             }
 32             //不阻止backspace
 33             if (e.KeyChar == 8)
 34             {
 35                 e.Handled = false;
 36             }
 37         }
 38 
 39         private void btnView_Click(object sender, EventArgs e)
 40         {
 41             //15位身份证组号:省(2)市(2)区[县](2)年(2)月(2)日+3序列号【奇数分配给男性/偶数分配给女性】
 42             //15升级到18位:第一点:出生年前面都加上19   第二点:第18位是校验位,也就是说第18位要从前17位计算而来
 43             //身份证分15位和18位两种
 44             //如果是15位身份证,取第7/8位就是出生年
 45             //如果是18位身份证,先校验用户输入的身份证是否合法,如果合法再取7-10位,就是出生年
 46             int age = 0;
 47             int year = 0;
 48             string id = txtId.Text.Trim();//Trim()    从当前字符串移除所有前导空白字符和尾随空白字符。
 49             if (id.Length == 15)//如果文本框的字符串长度等于15
 50             {
 51                 year = Convert.ToInt32(id.Substring(6, 2)) + 1900;//取出15位的身份证号的年份两位数并加够成为4位数(例如:94→1994)
 52                
 53                
 54             }
 55             else if (id.Length == 18)//如果文本框的字符串长度等于18
 56             {
 57                 if (!this.CheckCardId(id))//调用校验身份证号方法,false则执行下面代码
 58                 {
 59                     MessageBox.Show("身份证号码输入有误,请检查!18F");
 60                     return;//退出
 61                 }
 62                 year = Convert.ToInt32(id.Substring(6, 4));//取出18位的身份证号的年份
 63                 //age = DateTime.Now.Year - year;//计算年龄
 64             }
 65             else
 66             {
 67                 MessageBox.Show("身份证号码长度有误,请重新输入18S");
 68                 return;
 69             }
 70 
 71             age = DateTime.Now.Year - year;//计算年龄
 72             if (age >= 18)//如果年龄大于等于18岁,则执行
 73             {
 74                 pic.Visible = true;//图片显示
 75             }
 76             else
 77             {
 78                 MessageBox.Show("年龄过小,不符合要求");
 79                 return;
 80             }
 81         }
 82 
 83         /// <summary>
 84         /// 校验身份证号,如果正确则返回true,否则返回false
 85         /// </summary>
 86         /// <param name="id"></param>
 87         /// <returns></returns>
 88         private bool CheckCardId(string id)
 89         {
 90             int[] wQuan = {7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};//加权因子
 91             string checkWei = "10X98765432";//校验码
 92             string number17 = id.Substring(0,17);//前17位数
 93             string number18 = id.Substring(17);//第18位数
 94 
 95             int sum = 0;
 96             for (int i = 0; i < 17; i++)//把身份证号加权计算
 97             {
 98                 sum = sum + Convert.ToInt32(number17[i].ToString())*wQuan[i];
 99             }
100 
101             int mod = sum % 11;//计算模(关于取模的详细解释看例子后的注释)
102             string result = checkWei[mod].ToString();//根据模,查找得到对应的校验码并字符串化
103             if (number18.Equals(result, StringComparison.OrdinalIgnoreCase))//Equals确定两个 String 对象是否具有相同的值。  OrdinalIgnoreCase使用序号排序规则并忽略被比较字符串的大小写,对字符串进行比较。
104             {
105                 return true;//返回true
106             }
107             else
108             {
109                 return false;//返回false
110             }
111         }
112 
113         private void txtId_TextChanged(object sender, EventArgs e)//一旦文本框发生改变,图片变为不可显示
114         {
115             pic.Visible = false;//图片看见性为false
116         }
117     }
118 }
119 
120 /*
121  C语言中关于取模的解释:
122  
123 C中提供的取模(%)是用来求两个整数相除的余数
124 
125 如:
126 7/3=2...1
127 9/7=1...2
128 129 7%3=1
130 9%7=2
131 可以用来求余数,判断两个整数是否能整除
132 
133 CPU提供的指令只有整数取模,所以C提供的取模也是只能用整数来取模的(C语言比较接近底层)
134 直接把CPU的功能提供给编程人员,保持C的简洁性
135 
136 %符号还可以用字符来取模(偷偷地进行了类型转换)
137 
138 C语言函数库提供了浮点型的取模如fmod(),但 % 使用的是CPU指令,只能进行整数取模
139 */
原文地址:https://www.cnblogs.com/start-from-scratch/p/5071815.html