github.com/gogf/gf/v2@v2.7.4/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/gogf/gf.
     6  
     7  package builtin
     8  
     9  import (
    10  	"errors"
    11  	"strconv"
    12  	"strings"
    13  
    14  	"github.com/gogf/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  }