github.com/wangyougui/gf/v2@v2.6.5/util/gvalid/internal/builtin/builtin_resident_id.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/wangyougui/gf. 6 7 package builtin 8 9 import ( 10 "errors" 11 "strconv" 12 "strings" 13 14 "github.com/wangyougui/gf/v2/text/gregex" 15 ) 16 17 // RuleResidentId implements `resident-id` rule: 18 // Resident id number. 19 // 20 // Format: resident-id 21 type RuleResidentId struct{} 22 23 func init() { 24 Register(RuleResidentId{}) 25 } 26 27 func (r RuleResidentId) Name() string { 28 return "resident-id" 29 } 30 31 func (r RuleResidentId) Message() string { 32 return "The {field} value `{value}` is not a valid resident id number" 33 } 34 35 func (r RuleResidentId) Run(in RunInput) error { 36 if r.checkResidentId(in.Value.String()) { 37 return nil 38 } 39 return errors.New(in.Message) 40 } 41 42 // checkResidentId checks whether given id a china resident id number. 43 // 44 // xxxxxx yyyy MM dd 375 0 十八位 45 // xxxxxx yy MM dd 75 0 十五位 46 // 47 // 地区: [1-9]\d{5} 48 // 年的前两位:(18|19|([23]\d)) 1800-2399 49 // 年的后两位:\d{2} 50 // 月份: ((0[1-9])|(10|11|12)) 51 // 天数: (([0-2][1-9])|10|20|30|31) 闰年不能禁止29+ 52 // 53 // 三位顺序码:\d{3} 54 // 两位顺序码:\d{2} 55 // 校验码: [0-9Xx] 56 // 57 // 十八位:^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$ 58 // 十五位:^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$ 59 // 60 // 总: 61 // (^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$) 62 func (r RuleResidentId) checkResidentId(id string) bool { 63 id = strings.ToUpper(strings.TrimSpace(id)) 64 if len(id) != 18 { 65 return false 66 } 67 var ( 68 weightFactor = []int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2} 69 checkCode = []byte{'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'} 70 last = id[17] 71 num = 0 72 ) 73 for i := 0; i < 17; i++ { 74 tmp, err := strconv.Atoi(string(id[i])) 75 if err != nil { 76 return false 77 } 78 num = num + tmp*weightFactor[i] 79 } 80 if checkCode[num%11] != last { 81 return false 82 } 83 84 return gregex.IsMatchString( 85 `(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)`, 86 id, 87 ) 88 }