This commit is contained in:
guanguans 2021-01-11 17:55:24 +08:00
parent cf2ada4860
commit 26d7f5f009
9 changed files with 113 additions and 109 deletions

View File

@ -1,6 +1,7 @@
package id_validator
package idvalidator
import (
"errors"
"regexp"
"strconv"
"strings"
@ -8,29 +9,34 @@ import (
)
// 检查ID参数
func CheckIdArgument(id string) bool {
return len(GenerateType(id)) != 0
func CheckIDArgument(id string) bool {
_, err := GenerateCode(id)
return err == nil
}
// 生成数据
func GenerateType(id string) map[string]string {
lowerId := strings.ToLower(id)
if len(lowerId) == 15 {
return GenerateShortType(id)
func GenerateCode(id string) (map[string]string, error) {
length := len(id)
if length == 15 {
return GenerateShortCode(id)
}
if len(lowerId) == 18 {
return GenerateLongType(id)
if length == 18 {
return GenerateLongCode(id)
}
return map[string]string{}
return map[string]string{}, errors.New("Invalid ID card number length.")
}
// 生成短数据
func GenerateShortType(id string) map[string]string {
func GenerateShortCode(id string) (map[string]string, error) {
if len(id) != 15 {
return map[string]string{}, errors.New("Invalid ID card number length.")
}
mustCompile := regexp.MustCompile("(.{6})(.{6})(.{3})")
subMatch := mustCompile.FindStringSubmatch(id)
subMatch := mustCompile.FindStringSubmatch(strings.ToLower(id))
return map[string]string{
"body": subMatch[0],
@ -39,13 +45,16 @@ func GenerateShortType(id string) map[string]string {
"order": subMatch[3],
"checkBit": "",
"type": "15",
}
}, nil
}
// 生成长数据
func GenerateLongType(id string) map[string]string {
func GenerateLongCode(id string) (map[string]string, error) {
if len(id) != 18 {
return map[string]string{}, errors.New("Invalid ID card number length.")
}
mustCompile := regexp.MustCompile("((.{6})(.{8})(.{3}))(.)")
subMatch := mustCompile.FindStringSubmatch(id)
subMatch := mustCompile.FindStringSubmatch(strings.ToLower(id))
return map[string]string{
"body": subMatch[1],
@ -54,14 +63,12 @@ func GenerateLongType(id string) map[string]string {
"order": subMatch[4],
"checkBit": subMatch[5],
"type": "18",
}
}, nil
}
// 检查地址码
func CheckAddressCode(addressCode string, birthdayCode string) bool {
addressInfo := GetAddressInfo(addressCode, birthdayCode)
return addressInfo["province"] != ""
return GetAddressInfo(addressCode, birthdayCode)["province"] != ""
}
// 检查出生日期码
@ -71,9 +78,14 @@ func CheckBirthdayCode(birthdayCode string) bool {
return false
}
_, error := time.Parse("20060102", birthdayCode)
nowYear := time.Now().Year()
if year > nowYear {
return false
}
return error == nil
_, err := time.Parse("20060102", birthdayCode)
return err == nil
}
// 检查顺序码

View File

@ -5,7 +5,6 @@ package data
// 注1台湾省、香港特别行政区和澳门特别行政区暂缺地市和区县信息
// 注2每月发布的区划变更表是根据区划变更地的统计人员在统计信息系统更新后的情况所绘制与区划变更文件发布的时间有一定的延迟性但在每年的最后一次发布变更情况后与区划全年变更文件保持一致。
// Data Source: http://www.mca.gov.cn/article/sj/xzqh/
var AddressCode = map[int]string{
110000: "北京市",
110101: "东城区",

View File

@ -5,8 +5,7 @@ package data
// 注1台湾省、香港特别行政区和澳门特别行政区暂缺地市和区县信息
// 注2每月发布的区划变更表是根据区划变更地的统计人员在统计信息系统更新后的情况所绘制与区划变更文件发布的时间有一定的延迟性但在每年的最后一次发布变更情况后与区划全年变更文件保持一致。
// Data Source: http://www.mca.gov.cn/article/sj/xzqh/
var AddressCodeTimeline = map[int][4]map[string]string{
var AddressCodeTimeline = map[int][]map[string]string{
110000: {
{

View File

@ -1,7 +1,6 @@
package data
// 生肖信息
var ChineseZodiac = [12]string{
"子鼠",
"丑牛",

View File

@ -1,7 +1,6 @@
package data
// 星座信息
var Constellation = [13]map[string]string{
1: {
"name": "水瓶座",

View File

View File

@ -1,4 +1,4 @@
package id_validator
package idvalidator
import (
"id-validator/data"
@ -10,7 +10,7 @@ import (
"time"
)
// 生成 Bit
// 生成Bit码
func GeneratorCheckBit(body string) string {
// 位置加权
var posWeight [19]float64
@ -19,13 +19,13 @@ func GeneratorCheckBit(body string) string {
posWeight[i] = float64(weight)
}
// 累身份证号 body 部分与位置加权的积
bodySum := 0
// 累身份证号body部分与位置加权的积
var bodySum int
bodyArray := strings.Split(body, "")
count := len(bodyArray)
for i := 0; i < count; i++ {
bodySubStr, _ := strconv.Atoi(bodyArray[i])
bodySum += bodySubStr * int(posWeight[18-i])
bodySub, _ := strconv.Atoi(bodyArray[i])
bodySum += bodySub * int(posWeight[18-i])
}
// 生成校验码
@ -38,17 +38,15 @@ func GeneratorCheckBit(body string) string {
// 生成地址码
func GeneratorAddressCode(address string) string {
var addressCodeInt int
addressCode := ""
for code, addressStr := range data.AddressCode {
if address == addressStr {
addressCodeInt = code
addressCode = strconv.Itoa(code)
break
}
}
addressCode := strconv.Itoa(addressCodeInt)
classification := AddressCodeClassification(strconv.Itoa(addressCodeInt))
classification := AddressCodeClassification(addressCode)
switch classification {
case "country":
// addressCode = GetRandAddressCode("\\d{4}(?!00)[0-9]{2}$")
@ -97,7 +95,6 @@ func AddressCodeClassification(addressCode string) string {
// 获取随机地址码
func GetRandAddressCode(pattern string) string {
mustCompile := regexp.MustCompile(pattern)
var keys []string
for key := range data.AddressCode {
keyStr := strconv.Itoa(key)
@ -106,48 +103,55 @@ func GetRandAddressCode(pattern string) string {
}
}
// initialize global pseudo random generator
rand.Seed(time.Now().Unix())
randKey := rand.Intn(len(keys))
return keys[randKey]
return keys[rand.Intn(len(keys))]
}
// 生成出生日期码
func GeneratorBirthdayCode(birthday string) string {
year, _ := strconv.Atoi(DatePad(Substr(birthday, 0, 4), "year"))
month, _ := strconv.Atoi(DatePad(Substr(birthday, 4, 6), "month"))
day, _ := strconv.Atoi(DatePad(Substr(birthday, 6, 8), "day"))
year := DatePipelineHandle(DatePad(Substr(birthday, 0, 4), "year"), "year")
month := DatePipelineHandle(DatePad(Substr(birthday, 4, 6), "month"), "month")
day := DatePipelineHandle(DatePad(Substr(birthday, 6, 8), "day"), "day")
nowYear := time.Now().Year()
rand.Seed(time.Now().Unix())
if year < 1800 || year > nowYear {
randYear := rand.Intn(nowYear-1950) + 1950
year, _ = strconv.Atoi(DatePad(strconv.Itoa(randYear), "year"))
}
if month < 1 || month > 12 {
randMonth := rand.Intn(12-1) + 1
month, _ = strconv.Atoi(DatePad(strconv.Itoa(randMonth), "month"))
}
if day < 1 || day > 31 {
randDay := rand.Intn(28-1) + 1
day, _ = strconv.Atoi(DatePad(strconv.Itoa(randDay), "day"))
}
birthdayStr := DatePad(strconv.Itoa(year), "year") + DatePad(strconv.Itoa(month), "month") + DatePad(strconv.Itoa(day), "day")
_, error := time.Parse("20060102", birthdayStr)
birthday = year + month + day
_, error := time.Parse("20060102", birthday)
// example: 195578
if error != nil {
randYear := rand.Intn(nowYear-1950) + 1950
year, _ = strconv.Atoi(DatePad(strconv.Itoa(randYear), "year"))
randMonth := rand.Intn(12-1) + 1
month, _ = strconv.Atoi(DatePad(strconv.Itoa(randMonth), "month"))
randDay := rand.Intn(28-1) + 1
day, _ = strconv.Atoi(DatePad(strconv.Itoa(randDay), "day"))
year = DatePad(year, "year")
month = DatePad(month, "month")
day = DatePad(day, "day")
}
return DatePad(strconv.Itoa(year), "year") + DatePad(strconv.Itoa(month), "month") + DatePad(strconv.Itoa(day), "day")
return year + month + day
}
// 日期处理
func DatePipelineHandle(date string, category string) string {
dateInt, _ := strconv.Atoi(date)
switch category {
case "year":
nowYear := time.Now().Year()
rand.Seed(time.Now().Unix())
if dateInt < 1800 || dateInt > nowYear {
randDate := rand.Intn(nowYear-1950) + 1950
date = strconv.Itoa(randDate)
}
case "month":
if dateInt < 1 || dateInt > 12 {
randDate := rand.Intn(12-1) + 1
date = strconv.Itoa(randDate)
}
case "day":
if dateInt < 1 || dateInt > 31 {
randDate := rand.Intn(28-1) + 1
date = strconv.Itoa(randDate)
}
}
return date
}
// 生成顺序码
@ -155,7 +159,7 @@ func GeneratorOrderCode(sex int) string {
rand.Seed(time.Now().Unix())
orderCode := rand.Intn(999-111) + 111
if sex != orderCode%2 {
orderCode -= 1
orderCode--
}
return strconv.Itoa(orderCode)

View File

@ -1,10 +1,9 @@
package id_validator
package idvalidator
import (
"id-validator/data"
"strconv"
"strings"
"id-validator/data"
)
// 检查地址码
@ -16,8 +15,7 @@ func GetAddressInfo(addressCode string, birthdayCode string) map[string]string {
}
// 省级信息
provinceAddressCode := Substr(addressCode, 0, 2) + "0000"
addressInfo["province"] = GetAddress(provinceAddressCode, birthdayCode)
addressInfo["province"] = GetAddress(Substr(addressCode, 0, 2)+"0000", birthdayCode)
// 用于判断是否是港澳台居民居住证8字开头
firstCharacter := Substr(addressCode, 0, 1)
@ -27,8 +25,7 @@ func GetAddressInfo(addressCode string, birthdayCode string) map[string]string {
}
// 市级信息
cityAddressCode := Substr(addressCode, 0, 4) + "00"
addressInfo["city"] = GetAddress(cityAddressCode, birthdayCode)
addressInfo["city"] = GetAddress(Substr(addressCode, 0, 4)+"00", birthdayCode)
// 县级信息
addressInfo["district"] = GetAddress(addressCode, birthdayCode)
@ -36,22 +33,17 @@ func GetAddressInfo(addressCode string, birthdayCode string) map[string]string {
return addressInfo
}
// 获取省市区地址码
func GetAddress(addressCode string, birthdayCode string) string {
var address string
addressCodeStr, _ := strconv.Atoi(addressCode)
addressCodeTimeline := data.AddressCodeTimeline[addressCodeStr]
year := Substr(birthdayCode, 0, 4)
yearStr, _ := strconv.Atoi(year)
for key, val := range addressCodeTimeline {
if len(val) == 0 {
continue
}
address := ""
addressCodeInt, _ := strconv.Atoi(addressCode)
year, _ := strconv.Atoi(Substr(birthdayCode, 0, 4))
for key, val := range data.AddressCodeTimeline[addressCodeInt] {
// if len(val) == 0 {
// continue
// }
startYear, _ := strconv.Atoi(val["start_year"])
if (key == 0 && yearStr < startYear) || yearStr >= startYear {
if (key == 0 && year < startYear) || year >= startYear {
address = val["address"]
}
}
@ -91,7 +83,7 @@ func GetChineseZodiac(birthdayCode string) string {
// Substr 截取字符串
func Substr(source string, start int, end int) string {
var r = []rune(source)
r := []rune(source)
length := len(r)
if start < 0 || end > length || start > end {

View File

@ -1,4 +1,4 @@
package id_validator
package idvalidator
import (
"errors"
@ -8,12 +8,13 @@ import (
// 验证身份证号合法性
func IsValid(id string) bool {
if !CheckIdArgument(id) {
code, err := GenerateCode(id)
if err != nil {
return false
}
code := GenerateType(id)
if !CheckAddressCode(code["addressCode"], code["birthdayCode"]) || !CheckBirthdayCode(code["birthdayCode"]) || !CheckOrderCode(code["order"]) {
// 检查顺序码、生日码、地址码
if !CheckOrderCode(code["order"]) || !CheckBirthdayCode(code["birthdayCode"]) || !CheckAddressCode(code["addressCode"], code["birthdayCode"]) {
return false
}
@ -22,10 +23,8 @@ func IsValid(id string) bool {
return true
}
// 验证:校验码
checkBit := GeneratorCheckBit(code["body"])
return code["checkBit"] == checkBit
// 校验码
return code["checkBit"] == GeneratorCheckBit(code["body"])
}
// 获取身份证信息
@ -35,7 +34,7 @@ func GetInfo(id string) map[string]string {
return map[string]string{}
}
code := GenerateType(id)
code, _ := GenerateCode(id)
addressInfo := GetAddressInfo(code["addressCode"], code["birthdayCode"])
// fmt.Println(addressInfo)
@ -67,15 +66,15 @@ func GetInfo(id string) map[string]string {
return info
}
// 生成假数据
func FakeId(isEighteen bool, address string, birthday string, sex int) string {
// 生成假身份证号码
func Fake(isEighteen bool, address string, birthday string, sex int) string {
// 生成地址码
addressCode := GeneratorAddressCode(address)
// 出生日期码
birthdayCode := GeneratorBirthdayCode(birthday)
// fmt.Println(birthdayCode)
// 顺序码
// 生成顺序码
orderCode := GeneratorOrderCode(sex)
if !isEighteen {
@ -88,12 +87,13 @@ func FakeId(isEighteen bool, address string, birthday string, sex int) string {
}
// 15位升级18位号码
func UpgradeId(id string) (string, error) {
func Upgrade(id string) (string, error) {
if !IsValid(id) {
return "", errors.New("Not Valid ID card number.")
}
code := GenerateShortType(id)
code, _ := GenerateShortCode(id)
body := code["addressCode"] + code["birthdayCode"] + code["order"]
return body + GeneratorCheckBit(body), nil