go 초대 코드 생성, 가역

8111 단어 go
배경.
  • 일상적인 사이트 개발에서 사이트의 판촉 활동을 만나면 초청 선물과 관련된 기능이 있다
  • 친구 초대에 성공하면 해당 보상을 획득, 이때 요청 코드가 요구됩니다
  • 초대 번호는 사용자당 고유해야 함
  •    .       uid     
    
  •    .            id  ,      ,  code,  uid
    
  • 방법2, 이런 방식은 uid와 코드 관계를 추가로 기록해야 한다
  • 방법 1, uid에 따라 생성하고 코드에 따라 uid를 반출할 수 있으며 추가 조회를 하지 않아도 비교적 편리하다
  • 이루어지다
  • 기록 방법 1의 실현
  • 긴 숫자에서 특정 길이의 코드로 전환하려면 먼저 코드의 문자 범위를 확정해야 한다
  • 0-9A-Z 36진수로 변환하거나 소문자를 추가할 수 있음
  • 32진수로 변환
  • 01과 o가 혼동하기 쉬운 문자와 보정 문자 F를 제거하고 32자
  • 남음
    코드
    go 실현 방법 1
    package t
    
    import (
    	"errors"
    	"fmt"
    	"math/rand"
    	"strings"
    	"testing"
    	"time"
    )
    
    type code struct {
    	base    string //        , string  
    	decimal uint64 //     
    	pad     string //     ,    code      ,   +    ,             
    	len     int    // code    
    }
    
    func TestInviteCode(t *testing.T) {
    	inviteCode := code{
    		base:    "HVE8S2DZX9C7P5IK3MJUAR4WYLTN6BGQ",
    		decimal: 32,
    		pad:     "F",
    		len:     6,
    	}
    	//      
    	if res, err := inviteCode.initCheck(); !res {
    		fmt.Println(err)
    		return
    	}
    	id := uint64(1)
    	code := inviteCode.idToCode(1)
    	fmt.Printf("id=%v, code=%v
    ", id, code) code = "VFXXXX" id = inviteCode.codeToId(code) fmt.Printf("code=%v, id=%v
    ", code, id) } // 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 < c.len { res += c.pad for i := 0; i < c.len-resLen-1; i++ { rand.Seed(time.Now().UnixNano()) res += string(c.base[rand.Intn(int(c.decimal))]) } } return res } // code id func (c *code) codeToId(code string) uint64 { res := uint64(0) lenCode := len(code) //var baseArr [] byte = []byte(c.base) baseArr := []byte (c.base) // byte baseRev := make(map[byte]int) // map for k, v := range baseArr { baseRev[v] = k } // isPad := strings.Index(code, c.pad) if isPad != -1 { lenCode = isPad } r := 0 for i := 0; i < lenCode; i++ { // if string(code[i]) == c.pad { continue } index := baseRev[code[i]] b := uint64(1) for j := 0; j < r; j++ { b *= c.decimal } // pow float64 , , pow //res += float64(index) * math.Pow(float64(32), float64(2)) res += uint64(index) * b r++ } return res } // func (c *code) initCheck() (bool, error) { lenBase := len(c.base) // if c.base == "" { return false, errors.New("base string is nil or empty") } // if uint64(lenBase) != c.decimal { return false, errors.New("base length and len not match") } return true, errors.New("") }

     
    go 구현 2 (작자 원문 오류 b=32에서 b*=32로 변경, 사용 가능)
    package t
    
    import (
    	"container/list"
    	"errors"
    	"fmt"
    	"testing"
    )
    
    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
    ", 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 < 6; i++ { if i < 6-listLen { res = append(res, base[0]) } else { res = append(res, l.Front().Value.(byte)) l.Remove(l.Front()) } } return res } } func Base34ToNum(str []byte) (uint64, error) { if baseMap == nil { return 0, errors.New("no init base map") } if str == nil || len(str) == 0 { return 0, errors.New("parameter is nil or empty") } var res uint64 = 0 var r uint64 = 0 for i := len(str) - 1; 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 < r; j++ { b *= 32 } res += b * uint64(v) r++ } return res, nil } func TestInviteCode2(t *testing.T) { InitBaseMap() fmt.Printf("len(baseStr):%d, len(base):%d
    ", len(baseStr), len(base)) res := Base34(1544804416) fmt.Printf("=base:1544804416->%s, %d
    ", string(res), len(res)) str := "VIVZ4EH" num, err := Base34ToNum([]byte(str)) if err == nil { fmt.Printf("=base:%s->%d
    ", str, num) } else { fmt.Printf("===============err:%s
    ", err.Error()) } }

    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 < static::$code_min_len) {
                $result .= static::$pad;
                for ($i = 0; $i < static::$code_min_len - $code_len - 1; $i ++) {
                    $result .= static::$base[rand(0, static::$decimal_len -1)];
                }
            }
            return $result;
        }
     
        /**
         * code  id
         *   code       
         *        
         * eg: N8FASR, F    ,       
         * N ---> 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 < $len_real; $i ++) {
                $str = $code[$i];
                $index = $base_flip_map[$str] ?? '';
                if ($index === '') {
                    break;
                }
                $result += pow(static::$decimal_len, $i) * $index;
            }
            return $result;
        }
    }
    $num = "123";
    var_dump(ShareCodeUtils::idToCode($num));
    $code = "N8FMJ3";
    var_dump(ShareCodeUtils::codeToId($code));
     
    
    

     
    총결산
  • 이번 실현은 php와 고 두 언어로 이루어진다
  • 가장 큰 소감은 고의 유형 전환이 비교적 번거롭다는 것이다. 모두 강한 유형이기 때문이다
  • 와 php는 아직 다르다
  • 하지만 고의 문법 코드를 더 익힌 셈이다
  • 좋은 웹페이지 즐겨찾기