背景
- 日常的网站开发中,会遇到网站的促销活动,就有涉及到邀请好礼的功能
- 成功邀请好友,则获取相应奖励,这时候,就有邀请码的需求
- 邀请码要求每个用户唯一
方法一. 可根据用户的uid生成邀请码
方法二. 邀请码可根据某个初始化id生成,用户主动请求,生成code,绑定uid
- 方法二,这种方式,需额外记录uid和code关系
- 方法一,根据uid生成,也可根据code反推出uid,不用额外查询,比较方便
实现
- 记录方法一的实现
- 由长数字转换为特定长度的code,首先需确定code的字符范围
- 可转换为 0-9A-Z 36进制数,或者更多字符可添加小写字符
- 本次实现 转换为 32进制数
- 去掉0 1 和 o 容易混淆的字符和补位字符F,剩余32字符
代码
php实现
/**
* Class ShareCodeUtils
*
* 邀请码生成器,基本原理
* 1)参数用户ID
* 2)使用自定义进制转换之后为:V
* 3)最小code长度为6位,若不足则在后面添加分隔字符‘F‘:VF
* 4)在VF后面再随机补足4位,得到形如 VFAADD
* 5)反向转换时以‘F‘为分界线,‘F‘后面的不再解析
*/
class ShareCodeUtils {
// 32个进制字符(0,1 没加入,容易和 o l 混淆,O 未加入,F 未加入,用于补位)
// 顺序可进行调整, 增加反推难度
private static $base = [‘H‘, ‘V‘, ‘E‘, ‘8‘, ‘S‘, ‘2‘, ‘D‘, ‘Z‘, ‘X‘, ‘9‘, ‘C‘, ‘7‘, ‘P‘,‘5‘, ‘I‘, ‘K‘, ‘3‘, ‘M‘, ‘J‘, ‘U‘, ‘A‘, ‘R‘, ‘4‘, ‘W‘, ‘Y‘, ‘L‘, ‘T‘, ‘N‘, ‘6‘, ‘B‘, ‘G‘, ‘Q‘];
// F为补位字符,不能和上述字符重复
private static $pad = "F";
// 进制长度
private static $decimal_len = 32;
// 生成code最小长度
private static $code_min_len = 6;
/**
* id转为code
* 相除去模法
*
* @param $id
* @return string
*/
public static function idToCode($id)
{
$result = "";
while (floor($id / static::$decimal_len) > 0){
$index = $id % static::$decimal_len;
$result.= static::$base[$index];
$id = floor($id / static::$decimal_len);
}
$index = $id % static::$decimal_len;
$result.= static::$base[$index];
// code长度不足,则随机补全
$code_len = strlen($result);
if ($code_len 27
* 8 ---> 3
* 进制转换 27*32(0) + 3*32(1) = 123
* 32(0) ---> 32的0次方
* 32(1) ---> 32的1次方
*
* @param $code
* @return string
*/
public static function codeToId($code)
{
$result = 0;
$base_flip_map = array_flip(static::$base);
$is_pad = strpos($code, static::$pad);
if (!empty($is_pad)) {
$len_real = $is_pad;
} else {
$len_real = strlen($code);
}
for ($i = 0; $i
go实现
package main
import (
"errors"
"fmt"
"math/rand"
"strings"
"time"
)
type code struct {
base string // 进制的包含字符, string类型
decimal uint64 // 进制长度
pad string // 补位字符,若生成的code小于最小长度,则补位+随机字符, 补位字符不能在进制字符中
len int // code最小长度
}
// id转code
func (c *code) idToCode (id uint64) string {
mod := uint64(0)
res := ""
for id!=0 {
mod = id % c.decimal
id = id / c.decimal
res += string(c.base[mod])
}
resLen := len(res)
if resLen
go实现2
package main
import(
"container/list"
"errors"
"fmt"
)
var baseStr string = "HVE8S2DZX9C7P5IK3MJUAR4WYLTN6BGQ"
var base [] byte = []byte(baseStr)
var baseMap map[byte] int
func InitBaseMap(){
baseMap = make(map[byte]int)
for i, v := range base {
baseMap[v] = i
}
}
func Base34(n uint64)([]byte){
quotient := n
mod := uint64(0)
l := list.New()
for quotient != 0 {
//fmt.Println("---quotient:", quotient)
mod = quotient%32
quotient = quotient/32
l.PushFront(base[int(mod)])
//res = append(res, base[int(mod)])
//fmt.Printf("---mod:%d, base:%s\n", mod, string(base[int(mod)]))
}
listLen := l.Len()
if listLen >= 6 {
res := make([]byte,0,listLen)
for i := l.Front(); i != nil ; i = i.Next(){
res = append(res, i.Value.(byte))
}
return res
} else {
res := make([]byte,0,6)
for i := 0; i =0; i-- {
v, ok := baseMap[str[i]]
if !ok {
fmt.Printf("")
return 0, errors.New("character is not base")
}
var b uint64 = 1
for j:=uint64(0); j%s, %d\n", string(res), len(res))
str := "VIVZ4EH"
num, err := Base34ToNum([]byte(str))
if err == nil {
fmt.Printf("===============base:%s->%d\n", str, num)
} else {
fmt.Printf("===============err:%s\n", err.Error())
}
}
总结
- 本次实现由 php 和 go 两种语言实现
- 最大的心得就是 go中的 类型转换是比较麻烦的,因为都是强类型
- 和php 还不太一样
- 但也算是进一步熟悉了go的语法代码
原文地址:https://www.cnblogs.com/fanfan259/p/11423288.html
时间: 2024-10-09 12:56:12