@@ -0,0 +1,32 @@ | |||
package id_validator | |||
import ( | |||
"math" | |||
"strconv" | |||
"strings" | |||
) | |||
func GeneratorCheckBit(body string) string { | |||
// 位置加权 | |||
var posWeight [19]float64 | |||
for i := 2; i < 19; i++ { | |||
weight := int(math.Pow(2, float64(i-1))) % 11 | |||
posWeight[i] = float64(weight) | |||
} | |||
// 累身份证号 body 部分与位置加权的积 | |||
bodySum := 0 | |||
bodyArray := strings.Split(body, "") | |||
count := len(bodyArray) | |||
for i := 0; i < count; i++ { | |||
bodySubStr, _ := strconv.Atoi(bodyArray[i]) | |||
bodySum += bodySubStr * int(posWeight[18-i]) | |||
} | |||
// 生成校验码 | |||
checkBit := (12 - (bodySum % 11)) % 11 | |||
if checkBit == 10 { | |||
return "X" | |||
} | |||
return strconv.Itoa(checkBit) | |||
} |
@@ -0,0 +1,87 @@ | |||
package id_validator | |||
import ( | |||
"regexp" | |||
"strconv" | |||
"strings" | |||
"time" | |||
) | |||
// 检查ID参数 | |||
func CheckIdArgument(id string) bool { | |||
return len(GenerateType(id)) != 0 | |||
} | |||
// 生成数据 | |||
func GenerateType(id string) map[string]string { | |||
lowerId := strings.ToLower(id) | |||
if len(lowerId) == 15 { | |||
return GenerateShortType(id) | |||
} | |||
if len(lowerId) == 18 { | |||
return GenerateLongType(id) | |||
} | |||
return map[string]string{} | |||
} | |||
// 生成短数据 | |||
func GenerateShortType(id string) map[string]string { | |||
mustCompile := regexp.MustCompile("(.{6})(.{6})(.{3})") | |||
subMatch := mustCompile.FindStringSubmatch(id) | |||
return map[string]string{ | |||
"body": subMatch[0], | |||
"addressCode": subMatch[1], | |||
"birthdayCode": "19" + subMatch[2], | |||
"order": subMatch[3], | |||
"checkBit": "", | |||
"type": "15", | |||
} | |||
} | |||
// 生成长数据 | |||
func GenerateLongType(id string) map[string]string { | |||
mustCompile := regexp.MustCompile("((.{6})(.{8})(.{3}))(.)") | |||
subMatch := mustCompile.FindStringSubmatch(id) | |||
return map[string]string{ | |||
"body": subMatch[1], | |||
"addressCode": subMatch[2], | |||
"birthdayCode": subMatch[3], | |||
"order": subMatch[4], | |||
"checkBit": subMatch[5], | |||
"type": "18", | |||
} | |||
} | |||
// 检查地址码 | |||
func CheckAddressCode(addressCode string, birthdayCode string) bool { | |||
addressInfo := GetAddressInfo(addressCode, birthdayCode) | |||
if addressInfo["province"] == "" { | |||
return false | |||
} | |||
return true | |||
} | |||
// 检查出生日期码 | |||
func CheckBirthdayCode(birthdayCode string) bool { | |||
year, _ := strconv.Atoi(Substr(birthdayCode, 0, 4)) | |||
if year < 1800 { | |||
return false | |||
} | |||
_, error := time.Parse("20060102", birthdayCode) | |||
if error != nil { | |||
return false | |||
} | |||
return true | |||
} | |||
// 检查顺序码 | |||
func CheckOrderCode(orderCode string) bool { | |||
return len(orderCode) == 3 | |||
} |
@@ -0,0 +1,75 @@ | |||
package id_validator | |||
import ( | |||
"strconv" | |||
"id-validator/data" | |||
) | |||
// 检查地址码 | |||
func GetAddressInfo(addressCode string, birthdayCode string) map[string]string { | |||
addressInfo := map[string]string{ | |||
"province": "", | |||
"city": "", | |||
"district": "", | |||
} | |||
// 省级信息 | |||
provinceAddressCode := Substr(addressCode, 0, 2) + "0000" | |||
addressInfo["province"] = GetAddress(provinceAddressCode, birthdayCode) | |||
// 用于判断是否是港澳台居民居住证(8字开头) | |||
firstCharacter := Substr(addressCode, 0, 1) | |||
// 港澳台居民居住证无市级、县级信息 | |||
if firstCharacter == "8" { | |||
return addressInfo | |||
} | |||
// 市级信息 | |||
cityAddressCode := Substr(addressCode, 0, 4) + "00" | |||
addressInfo["city"] = GetAddress(cityAddressCode, birthdayCode) | |||
// 县级信息 | |||
addressInfo["district"] = GetAddress(addressCode, birthdayCode) | |||
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 | |||
} | |||
startYear, _ := strconv.Atoi(val["start_year"]) | |||
if (key == 0 && yearStr < startYear) || yearStr >= startYear { | |||
address = val["address"] | |||
} | |||
} | |||
return address | |||
} | |||
// Substr 截取字符串 | |||
func Substr(source string, start int, end int) string { | |||
var r = []rune(source) | |||
length := len(r) | |||
if start < 0 || end > length || start > end { | |||
return "" | |||
} | |||
if start == 0 && end == length { | |||
return source | |||
} | |||
return string(r[start:end]) | |||
} |
@@ -0,0 +1,23 @@ | |||
package id_validator | |||
// 验证身份证号合法性 | |||
func IsValid(id string) bool { | |||
if !CheckIdArgument(id) { | |||
return false | |||
} | |||
code := GenerateType(id) | |||
if !CheckAddressCode(code["addressCode"], code["birthdayCode"]) || !CheckBirthdayCode(code["birthdayCode"]) || !CheckOrderCode(code["order"]) { | |||
return false | |||
} | |||
// 15位身份证不含校验码 | |||
if code["type"] == "15" { | |||
return true | |||
} | |||
// 验证:校验码 | |||
checkBit := GeneratorCheckBit(code["body"]) | |||
return code["checkBit"] == checkBit | |||
} |