Go验证身份证号

大地缸 · · 3678 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。


title: "Go验证身份证号"
date: 2021-02-10T07:54:44+08:00
draft: true
tags: ['go']
author: "dadigang"
author_cn: "大地缸"
personal: "http://www.real007.cn"


关于作者

http://www.real007.cn/about

golang 身份证信息处理

功能简单介绍:针对一串身份证字符串(string)的处理:

1. 验证身份证的正确性

2. 提取出生年月日

3. 提取性别

4. 把15位的身份证号码转成18位

5. 验证省份代码正确性

直接上代码:

package citizen

import (
    "strconv"
    "errors"
    "time"
)

var weight = [17]int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
var valid_value = [11]byte{'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'}
var valid_province = []string{
    "11",           // 北京市
    "12",           // 天津市
    "13",           // 河北省
    "14",           // 山西省
    "15",           // 内蒙古自治区
    "21",           // 辽宁省
    "22",           // 吉林省
    "23",           // 黑龙江省
    "31",           // 上海市
    "32",           // 江苏省
    "33",           // 浙江省
    "34",           // 安徽省
    "35",           // 福建省
    "36",           // 山西省
    "37",           // 山东省
    "41",           // 河南省
    "42",           // 湖北省
    "43",           // 湖南省
    "44",           // 广东省
    "45",           // 广西壮族自治区
    "46",           // 海南省
    "50",           // 重庆市
    "51",           // 四川省
    "52",           // 贵州省
    "53",           // 云南省
    "54",           // 西藏自治区
    "61",           // 陕西省
    "62",           // 甘肃省
    "63",           // 青海省
    "64",           // 宁夏回族自治区
    "65",           // 新疆维吾尔自治区
    "71",           // 台湾省
    "81",           // 香港特别行政区
    "91",           // 澳门特别行政区
}

// Check citizen number 18 valid.
func IsValidCitizenNo18(citizenNo18 *[]byte) bool {
    nLen := len(*citizenNo18)
    if nLen != 18 {
        return false
    }

    nSum := 0
    for i := 0; i < nLen - 1; i++ {
        n, _ := strconv.Atoi(string((*citizenNo18)[i]))
        nSum += n * weight[i]
    }
    mod := nSum % 11
    if valid_value[mod] == (*citizenNo18)[17] {
        return true
    }

    return false
}

// Convert citizen 15 to 18.
func Citizen15To18(citizenNo15 []byte) []byte {
    nLen := len(citizenNo15)
    if nLen != 15 {
        return nil
    }

    citizenNo18 := make([]byte, 0)
    citizenNo18 = append(citizenNo18, citizenNo15[:6]...)
    citizenNo18 = append(citizenNo18, '1', '9');
    citizenNo18 = append(citizenNo18, citizenNo15[6:]...)

    sum := 0
    for i, v := range citizenNo18 {
        n, _ := strconv.Atoi(string(v))
        sum += n * weight[i]
    }
    mod := sum % 11
    citizenNo18 = append(citizenNo18, valid_value[mod])

    return citizenNo18
}

func IsLeapYear(nYear int) bool {
    if nYear <= 0 {
        return false
    }

    if (nYear % 4 == 0 && nYear % 100 != 0) || nYear % 400 == 0 {
        return true
    }

    return false
}

// Check birthday's year month day valid.
func CheckBirthdayValid(nYear, nMonth, nDay int) bool {
    if nYear < 1900 || nMonth <= 0 || nMonth > 12 || nDay <= 0 || nDay > 31 {
        return false
    }

    curYear, curMonth, curDay := time.Now().Date()
    if nYear == curYear {
        if nMonth > int(curMonth) {
            return false
        } else if nMonth == int(curMonth) && nDay > curDay {
            return false
        }
    }

    if 2 == nMonth {
        if IsLeapYear(nYear) && nDay > 29 {
            return false
        } else if nDay > 28 {
            return false
        }
    } else if 4 == nMonth || 6 == nMonth || 9 == nMonth || 11 == nMonth {
        if nDay > 30 {
            return false
        }
    }

    return true
}

// Check province code valid.
func CheckProvinceValid(citizenNo []byte) bool {
    provinceCode := make([]byte, 0)
    provinceCode = append(provinceCode, citizenNo[:2]...)
    provinceStr := string(provinceCode)

    for i, _ := range valid_province {
        if provinceStr == valid_province[i] {
            return true
        }
    }

    return false
}

// Check citizen number valid.
func IsValidCitizenNo(citizenNo *[]byte) bool {
    nLen := len(*citizenNo)
    if nLen != 15 && nLen != 18 {
        return false
    }

    for i, v := range *citizenNo {
        n, _ := strconv.Atoi(string(v))
        if n >= 0 && n <= 9 {
            continue
        }

        if v == 'X' && i == 16 {
            continue
        }

        return false
    }

    if !CheckProvinceValid(*citizenNo) {
        return false
    }

    if nLen == 15 {
        *citizenNo = Citizen15To18(*citizenNo)
        if citizenNo == nil {
            return false
        }
    } else if !IsValidCitizenNo18(citizenNo) {
        return false
    }

    nYear, _ := strconv.Atoi(string((*citizenNo)[6:10]))
    nMonth, _ := strconv.Atoi(string((*citizenNo)[10:12]))
    nDay, _ := strconv.Atoi(string((*citizenNo)[12:14]))
    if !CheckBirthdayValid(nYear, nMonth, nDay) {
        return false
    }

    return true
}

// Get information from citizen number. Birthday, gender, province mask.
func GetCitizenNoInfo(citizenNo []byte) (err error, birthday int64, isMale bool, addrMask int) {
    err = nil
    birthday = 0
    isMale = false
    addrMask = 0
    if !IsValidCitizenNo(&citizenNo) {
        err = errors.New("Invalid citizen number.")
        return
    }

    // Birthday information.
    nYear, _ := strconv.Atoi(string(citizenNo[6:10]))
    nMonth, _ := strconv.Atoi(string(citizenNo[10:12]))
    nDay, _ := strconv.Atoi(string(citizenNo[12:14]))
    birthday = time.Date(nYear, time.Month(nMonth), nDay, 0, 0, 0, 0, time.Local).Unix()

    // Gender information.
    genderMask, _ := strconv.Atoi(string(citizenNo[16]))
    if genderMask % 2 == 0 {
        isMale = false
    } else {
        isMale = true
    }

    // Address code mask.
    addrMask, _ = strconv.Atoi(string(citizenNo[:2]))

    return
}

测试代码:

package main

import (
    "fmt"
    "go_code/citizentest/citizen"
)

func main() {
    // citizenNo := []byte("340321199001234560")
    citizenNo := []byte("340321900123456")
    err, birthday, isMale, addrMask := citizen.GetCitizenNoInfo(citizenNo)
    if err != nil {
        fmt.Println("Invalid citizen number.")
    } else {
            fmt.Println("Valid citizen number.")
            fmt.Printf("Information from citizen: birthday=%v, ismale=%v, addrmask=%d\n", birthday, isMale, addrMask)
    }
}


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:大地缸

查看原文:Go验证身份证号

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:701969077

3678 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传