github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/chinaid/api.go (about)

     1  package chinaid
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"math"
     7  	"math/rand"
     8  	"strconv"
     9  	"time"
    10  )
    11  
    12  // ProvinceAndCity 返回随机省/城市
    13  func ProvinceAndCity() string {
    14  	return ProvinceCity[RandInt(0, len(ProvinceCity))]
    15  }
    16  
    17  // Address 返回随机地址
    18  func Address() string {
    19  	return ProvinceAndCity() +
    20  		RandChinese(2, 3) + "路" +
    21  		strconv.Itoa(RandInt(1, 8000)) + "号" +
    22  		RandChinese(2, 3) + "小区" +
    23  		strconv.Itoa(RandInt(1, 20)) + "单元" +
    24  		strconv.Itoa(RandInt(101, 2500)) + "室"
    25  }
    26  
    27  // BankNo 返回随机银行卡号,银行卡号符合LUHN 算法并且有正确的卡 bin 前缀
    28  func BankNo() string {
    29  	// 随机选中银行卡卡头
    30  	bank := CardBins[RandInt(0, len(CardBins))]
    31  	// 获取 卡前缀(cardBin)
    32  	prefixes := bank.Prefixes
    33  	// 获取当前银行卡正确长度
    34  	cardNoLength := bank.Length
    35  	// 生成 长度-1 位卡号
    36  	preCardNo := strconv.Itoa(prefixes[RandInt(0, len(prefixes))]) +
    37  		fmt.Sprintf("%0*d", cardNoLength-7, RandInt64(0, int64(math.Pow10(cardNoLength-7))))
    38  	// LUHN 算法处理
    39  	return LUHNProcess(preCardNo)
    40  }
    41  
    42  // LUHNProcess 通过 LUHN 合成卡号处理给定的银行卡号
    43  func LUHNProcess(preCardNo string) string {
    44  	checkSum := 0
    45  	tmpCardNo := reverseString(preCardNo)
    46  	for i, s := range tmpCardNo {
    47  		// 数据层确保卡号正确
    48  		tmp, _ := strconv.Atoi(string(s))
    49  		// 由于卡号实际少了一位,所以反转后卡号第一位一定为偶数位
    50  		// 同时 i 正好也是偶数,此时 i 将和卡号奇偶位同步
    51  		if i%2 == 0 {
    52  			// 偶数位 *2 是否为两位数(>9)
    53  			if tmp*2 > 9 {
    54  				// 如果为两位数则 -9
    55  				checkSum += tmp*2 - 9
    56  			} else {
    57  				// 否则直接相加即可
    58  				checkSum += tmp * 2
    59  			}
    60  		} else {
    61  			// 奇数位直接相加
    62  			checkSum += tmp
    63  		}
    64  	}
    65  	if checkSum%10 != 0 {
    66  		return preCardNo + strconv.Itoa(10-checkSum%10)
    67  	} else {
    68  		// 如果不巧生成的前 卡长度-1 位正好符合 LUHN 算法
    69  		// 那么需要递归重新生成(需要符合 cardBind 中卡号长度)
    70  		return BankNo()
    71  	}
    72  }
    73  
    74  // Email 返回随机邮箱,邮箱目前只支持常见的域名后缀
    75  func Email() string {
    76  	return RandSmallLetters(8) + "@" + RandSmallLetters(5) + DomainSuffix[RandInt(0, len(DomainSuffix))]
    77  }
    78  
    79  // IssueOrg 返回身份证签发机关(eg: XXX公安局/XX区分局)
    80  func IssueOrg() string {
    81  	return CityName[RandInt(0, len(CityName))] + "公安局某某分局"
    82  }
    83  
    84  // ValidPeriod 返回身份证有效期限(eg: 20150906-20350906),有效期限固定为 20 年
    85  func ValidPeriod() string {
    86  	begin := RandDate()
    87  	end := begin.AddDate(20, 0, 0)
    88  	return begin.Format("20060102") + "-" + end.Format("20060102")
    89  }
    90  
    91  // ChinaID 返回中国大陆地区身份证号.
    92  func ChinaID() string {
    93  	// AreaCode 随机一个+4位随机数字(不够左填充0)
    94  	areaCode := AreaCode[RandInt(0, len(AreaCode))] +
    95  		fmt.Sprintf("%0*d", 4, RandInt(1, 9999))
    96  	birthday := RandDate().Format("20060102")
    97  	randomCode := fmt.Sprintf("%0*d", 3, RandInt(0, 999))
    98  	prefix := areaCode + birthday + randomCode
    99  	return prefix + verifyCode(prefix)
   100  }
   101  
   102  // verifyCode 通过给定的身份证号生成最后一位的 verifyCode
   103  func verifyCode(cardId string) string {
   104  	tmp := 0
   105  	for i, v := range Wi {
   106  		t, _ := strconv.Atoi(string(cardId[i]))
   107  		tmp += t * v
   108  	}
   109  	return ValCodeArr[tmp%11]
   110  }
   111  
   112  // RandDate 返回随机时间,时间区间从 1970 年 ~ 2020 年
   113  func RandDate() time.Time {
   114  	begin, _ := time.Parse("2006-01-02 15:04:05", "1970-01-01 00:00:00")
   115  	end, _ := time.Parse("2006-01-02 15:04:05", "2020-01-01 00:00:00")
   116  	return RandDateRange(begin, end)
   117  }
   118  
   119  // RandDateRange 返回随机时间,时间区间从 1970 年 ~ 2020 年
   120  func RandDateRange(from, to time.Time) time.Time {
   121  	return time.Unix(RandInt64(from.Unix(), to.Unix()), 0)
   122  }
   123  
   124  // Mobile 返回中国大陆地区手机号
   125  func Mobile() string {
   126  	return MobilePrefix[RandInt(0, len(MobilePrefix))] + fmt.Sprintf("%0*d", 8, RandInt(0, 100000000))
   127  }
   128  
   129  // Sex 返回性别
   130  func Sex() string {
   131  	if RandInt(0, 2) == 0 {
   132  		return "男"
   133  	}
   134  	return "女"
   135  }
   136  
   137  // Name 返回中国姓名,姓名已经尽量返回常用姓氏和名字
   138  func Name() string {
   139  	return Surnames[RandInt(0, len(Surnames))] + RandChineseN(2)
   140  }
   141  
   142  // RandChineseN 指定长度随机中文字符(包含复杂字符)。
   143  func RandChineseN(n int) string {
   144  	var buf bytes.Buffer
   145  	for i := 0; i < n; i++ {
   146  		buf.WriteRune(rune(RandInt(19968, 40869)))
   147  	}
   148  	return buf.String()
   149  }
   150  
   151  // RandChinese 指定范围随机中文字符.
   152  func RandChinese(minLen, maxLen int) string {
   153  	return RandChineseN(RandInt(minLen, maxLen))
   154  }
   155  
   156  // RandSmallLetters 随机英文小写字母.
   157  func RandSmallLetters(len int) string {
   158  	data := make([]byte, len)
   159  	for i := 0; i < len; i++ {
   160  		data[i] = byte(rand.Intn(26) + 97)
   161  	}
   162  	return string(data)
   163  }
   164  
   165  // RandInt 指定范围随机 int
   166  func RandInt(min, max int) int {
   167  	if min >= max {
   168  		return min
   169  	}
   170  
   171  	return min + rand.Intn(max-min)
   172  }
   173  
   174  // RandInt64 指定范围随机 int64
   175  func RandInt64(min, max int64) int64 {
   176  	return min + rand.Int63n(max-min)
   177  }
   178  
   179  // 反转字符串
   180  func reverseString(s string) string {
   181  	runes := []rune(s)
   182  	for from, to := 0, len(runes)-1; from < to; from, to = from+1, to-1 {
   183  		runes[from], runes[to] = runes[to], runes[from]
   184  	}
   185  	return string(runes)
   186  }