VB.net编写的身份证类

这是我这几天,重新修订的身份证类。

主要功能是:

可以将以前旧的15位身份证转化为18位(考虑到15位身份证号存在时间较早,只在第6位后插入19,而不是插入20)。
可以验证身份证号码是否正确。
可以获得性别、年龄。
如果能够加载行政区划数据,则可以进行相应的验证。

考虑到现实中的实际运用,行政区划代码是否找到,不作为判断身份证是否正确的必要依据。因为行政区划代码经常有调整,很担心误判。可以按我程序的方法,结合行政区划代码的*号来判断身份证号是否正确。

现将全部代码分享于后。

vbnet 复制代码
Public Class BqSfz2


#Region "私有变量"

    '在身份证验证过程中,获得以下变量变量的值
    Private lsfzText As String = ""   ' 格式化后的身份证号(统一大写,去除空格)
    Private lRQbirth As String = ""   ' 出生日期(格式:YYYY-MM-DD)
    Private lSexText As String = ""   ' 性别("男"或"女")
    Private lsLevelC As String = ""   ' 行政区划代码(带*表示未在行政区划表中找到)

    '校验码计算相关常量 (GB 11643-1999标准)
    '直接在这里定义,而不是在mGetCheck2中,以提高运行的速度

    ' 权重因子数组
    Private lsWeightS() As Integer = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
    '定义校验码映射表(余数0-10对应的校验码)
    Private lsCheckDigitS() As String = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"}


    '以下是解决可以判定行政区划的问题
    '基本思路:
    ' 1、先加载行政区划的数据,如果加载成功,则进行行政区划的判断,如果没成功,则不判断
    ' 2、加载后,对行政区划编码进行搜索判断,如果找到,则正确,并获得行政区划代码;如果没有找到,则提示没找到,在区划代码前边加*号
    ' 3、行政区划是否找到,不作为判断身份证是否正确的必要依据。因为数据有调整,很担心误判。可以按我程序的方法,结合行政区划代码的*号来判断
    ' 4、这里只编写用数据表的方法。(也可以把行政区划及代码写入XML文件,读取后,进行查找验证。

    Private lYnLoadArea As Boolean = False    ' 是否已加载行政区划数据
    Private loTabArea As DataTable = Nothing  ' 行政区划数据表
    Private ltv As DataView = Nothing         ' 用于快速查找的数据视图




#End Region

#Region "公共属性"


    '验证传入的身份证号码是否正确
    Public ReadOnly Property BqPbIsRight(ByVal lstrSfz As String) As Boolean
        Get
            Return mGetRight(lstrSfz) ' 调用内部验证方法
        End Get
    End Property

    ' 属性:获取格式化后的身份证号(去除空格,统一大写)
    Public ReadOnly Property BqPsTrim() As String
        Get
            Return lsfzText
        End Get
    End Property   '格式化后的身份证号

    ' 属性:获取性别名称("男"或"女")
    Public ReadOnly Property BqPsSex() As String
        Get
            Return lSexText
        End Get
    End Property    '性别名称

    ' 属性:获取性别布尔值(False=女,True=男)
    Public ReadOnly Property BqPbSex() As Boolean
        Get
            Return IIf(lSexText = "女", False, True)
        End Get
    End Property   '性别 false 0 女生,ture 1 男生

    ' 属性:获取出生日期(格式:YYYY-MM-DD)
    Public ReadOnly Property BqPsBirth() As String
        Get
            Return lRQbirth
        End Get
    End Property  '出生日期

    ' 属性:将15位身份证转换为18位
    Public ReadOnly Property BqPsTo18(ByVal lstrSfz As String) As String
        Get
            Dim m0 As String = ""
            If mGetRight(lstrSfz) = True Then
                If lsfzText.Length = 15 Then
                    ' 15位转18位算法
                    Dim m1, m2 As String
                    m1 = lsfzText
                    m1 = Left(m1, 6) + "19" + Right(m1, 9) ' 在6位后插入19
                    m2 = mGetCheck1(m1)   '计算校验位,旧方法
                    m0 = m1 + m2
                Else ' 已经是18位的
                    m0 = lsfzText
                End If
            End If
            Return m0
        End Get
    End Property   '将15的升为18位

    ' 属性:计算到当前日期的年龄(基于身份证出生日期)
    Public ReadOnly Property BqPsOld() As String
        Get
            Return mGetOld(lRQbirth, Now)
        End Get
    End Property  '到 Now的年龄

    ' 属性:计算到指定日期的年龄(基于身份证出生日期)
    Public ReadOnly Property BqPsOld(ByVal lBeginDate As DateTime) As String
        Get
            Return mGetOld(lRQbirth, lBeginDate)
        End Get
    End Property  '到 Now的年龄

    '以下是解决对身份证前6位,行政区划的验证的思路
    '传入的是数据库
    Public Property BqpTabArea(ByVal lTabArea As DataTable) As Boolean
        Get
            Return lYnLoadArea
        End Get
        Set(ByVal Value As Boolean)
            lYnLoadArea = False
            loTabArea = lTabArea
            ltv = lTabArea.DefaultView
            If IsNothing(loTabArea) = False AndAlso loTabArea.Rows.Count > 2000 Then
                lYnLoadArea = True
            End If
        End Set
    End Property

    '读取行政区划,快速定位找到
    Public ReadOnly Property BqpAreaLevel() As String
        Get
            Return mGetCheckLevel()
        End Get
    End Property


#End Region

#Region "内部方法  "

    ''' <summary>
    ''' 核心验证方法 - 验证身份证有效性并提取信息
    ''' </summary>
    '验证身份证号码有效性
    Private Function mGetRight(ByVal lstrSfz As String) As Boolean
        Dim m0 As Boolean = False
        ' 清空前次验证结果
        lsfzText = ""    ' 整理后的身份证号(统一格式)
        lRQbirth = ""    ' 生日(格式:YYYY-MM-DD)
        lSexText = ""    ' 性别("男"或"女")
        lsLevelC = ""

        Dim s, ls1, ls2, ls3, ls4, ls5, ls6, ls7, ls9 As String

        ' 预处理身份证号码:去除空格、统一X的大小写、去除特殊字符
        s = "" & lstrSfz.ToString
        s = s.Replace(" ", "").Replace(" ", "").Replace("X", "X").Replace("x", "X")
        s = s.Replace("e", "").Replace("+", "")

        ' 只处理15位或18位身份证号
        If s.Length = 15 Or s.Length = 18 Then
            Try
                If s.Length = 15 Then
                    ls1 = s                           ' 完整15位号码
                    ls2 = ""                          ' 15位无校验码
                    ls3 = "19" & s.Substring(6, 6)    ' 生日部分(补19前缀)
                    ls4 = s.Substring(14, 1)          ' 性别位(15位的最后一位)
                    ls5 = ""                          ' 无需计算校验码
                    ls6 = "" & IsNumeric(ls1)         ' 检查是否全数字
                ElseIf s.Length = 18 Then
                    ls1 = s.Substring(0, 17)           ' 前17位
                    ls2 = s.Substring(17, 1).ToUpper   ' 校验位(转为大写)
                    ls3 = s.Substring(6, 8)            ' 生日部分(8位)
                    ls4 = s.Substring(16, 1)           ' 性别位(第17位)
                    ls5 = ""                           ' 待计算的校验码
                    ls6 = "" & IsNumeric(ls1)          ' 检查前17位是否全数字
                    If ls6 = "True" Then
                        ls5 = mGetCheck2(ls1)       '计算校验位,这是新方法
                        ls9 = mGetCheck1(ls1)       '这是旧方法
                        If ls5 <> ls9 Then          '主要是验证两种方法的一致性,正式使用时,可以把旧方法备注掉
                            MessageBox.Show("两种验证方法获取的验证码出错")
                        End If
                    End If
                End If

                '格式化日期字符串
                ls7 = ls3.Substring(0, 4) & "-" & ls3.Substring(4, 2) & "-" & ls3.Substring(6, 2)

                ' 验证条件:日期有效、校验码匹配、全数字(15位)或前17位全数字(18位)
                m0 = IIf(IsDate(ls7) = False Or ls2 <> ls5 Or ls6 = "False", False, True)
            Catch ex As Exception
                '出现异常视为无效身份证号
            End Try
        End If

        If m0 = True Then ' 验证通过,保存格式化后的信息
            lsfzText = s.ToUpper                   '统一转为大写
            lRQbirth = IIf(IsDate(ls7), ls7, "")   '格式化后的日期
            lSexText = IIf("24680".IndexOf(ls4) >= 0, "女", "男") '偶数为女,奇数为男
        End If

        Return m0
    End Function

    '年龄计算改进。(到指定的指定日期)
    Private Function mGetOld(ByVal lBirth As String, ByVal m2 As DateTime) As String
        Dim n As Integer = 0
        Try
            If IsDate(lBirth) Then
                Dim m1 As Date = CDate(lBirth)
                n = m2.Year - m1.Year
                If m1.Month < m1.Month Or (m1.Month = m1.Month And m1.Day < m1.Day) Then
                    n -= 1
                End If
            End If
        Catch ex As Exception
        End Try
        Return IIf(n = 0, "", "" & n)
    End Function

    '根据17位计算校验码。这是方法一 (保留的意义在于与方法二进行对比,可以在mGetRight中将其备注掉)
    Private Function mGetCheck1(ByVal m17 As String) As String
        '因为在内部用,m17肯定是17位的,所以就忽略是否是17位的验证
        Dim m0 As String = ""
        Dim i, n, m1 As Integer
        n = 0   ' 计算校验位
        For i = 18 To 2 Step -1
            m1 = CInt(Mid(m17, 19 - i, 1))
            n = n + (2 ^ (i - 1) Mod 11) * m1
        Next i
        n = n Mod 11
        ' 根据模11结果确定校验码
        m0 = IIf(n = 0, "1", IIf(n = 1, "0", IIf(n = 2, "X", Trim(Str(12 - n)))))
        Return m0
    End Function

    '根据17位计算校验码。这是方法二 更清晰,更符合新国标〖GB 11643-1999〗
    Private Function mGetCheck2(ByVal m17 As String) As String
        Dim m0 As String = ""
        Dim i, n, m1 As Integer
        n = 0    '加权和
        For i = 1 To 17
            m1 = CInt(Mid(m17, i, 1))
            n = n + m1 * lsWeightS(i - 1) '与权重因子的积进行累加
        Next
        n = n Mod 11
        m0 = lsCheckDigitS(n)          '根据余数返回对应的校验码
        Return m0
    End Function


    '验证行政区划
    Private Function mGetCheckLevel() As String
        '结果有两种情况:身份证前六位;没在行政区划表里找到,则加*;身份证有错就返回空值
        Dim m0 As String = ""
        Dim s As String = ""
        If lsfzText.Length > 6 Then
            s = Mid(lsfzText, 1, 6)  '取前6位
            Try
                If IsNothing(ltv) = True Then
                    m0 = s & "*"
                Else
                    ltv.Sort = "BhDq"
                    m0 = IIf(ltv.Find(s) > 0, s, s & "*")
                End If
            Catch ex As Exception
            End Try
        End If
        Return m0
    End Function



#End Region



End Class

如果再结合行政区划数据,可以将身份证类进一步扩充:

可以获得身份证号对应的省、市、县级行政区划代码或名称。

如果再结合农历数据,可以将身份证类进一步扩充:

获得农历生日、生肖、星座等。

身份证号码验证原理,可以参见我在2006年的写的文章:

身份证号码的秘密_没有0的身份证号码 上个世纪 11 12-CSDN博客

测试代码:

在新建窗口中,建立一个文本框TextBox1、一个列表ListBox1、一个命令按钮Button1。然后在命令按钮中,写入以下代码:

vbnet 复制代码
 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Me.ListBox1.DataSource = Nothing
        Dim k As Date = DateAdd(DateInterval.Day, -1000, Now)
        Dim mm As String
        mm = Me.TextBox1.Text
        Dim m(9) As String
        Dim lsfz As New BqSfz2
        With lsfz
            m(0) = "转18位:" & .BqPsTo18(mm)
            m(1) = "正确否:" & .BqPbIsRight(mm)
            m(2) = "性别:" & .BqPbSex()
            m(3) = "性别:" & .BqPsSex()
            m(4) = "生日:" & .BqPsBirth()
            m(5) = "规范后:" & .BqPsTrim()
            m(6) = "年龄:根据身份证号来计算:" & .BqPsOld()
            m(7) = "年龄:根据生日来计算:" & .BqPsOld()
            m(8) = "1000天前的年龄:" & .BqPsOld(k)
            'If .BqpTabArea(ltb) = True Then
            '    '这一段移到学校管理系统中去测试
            'End If
            m(9) = "地区编码:" & .BqpAreaLevel
        End With
        Me.ListBox1.DataSource = m
    End Sub
相关推荐
RadiumAg40 分钟前
记一道有趣的面试题
前端·javascript
yangzhi_emo1 小时前
ES6笔记2
开发语言·前端·javascript
yanlele1 小时前
我用爬虫抓取了 25 年 5 月掘金热门面试文章
前端·javascript·面试
SEO-狼术1 小时前
Highcharts Dashboards provides crack
.net
中微子2 小时前
React状态管理最佳实践
前端
烛阴2 小时前
void 0 的奥秘:解锁 JavaScript 中 undefined 的正确打开方式
前端·javascript
中微子2 小时前
JavaScript 事件与 React 合成事件完全指南:从入门到精通
前端
Hexene...3 小时前
【前端Vue】如何实现echarts图表根据父元素宽度自适应大小
前端·vue.js·echarts
天天扭码3 小时前
《很全面的前端面试题》——HTML篇
前端·面试·html
xw53 小时前
我犯了错,我于是为我的uni-app项目引入环境标志
前端·uni-app