snippetgoMinor
Convert int64 to custom base64 number string
Viewed 0 times
numberconvertint64custombase64string
Problem
I want to convert
Is this implementation correct/efficient?
int64 to custom base 64 number string, with this specification:0..9 -> 0..9
10..35 -> a..z
36..61 -> A..Z
62 -> _
63 -> -Is this implementation correct/efficient?
func EncodeLogKey(id int64) string {
str := make([]byte,0,12)
if id == 0 { return "0" }
for id>0 {
var ch rune
mod := rune(id % 64)
if mod = '0' && ch = 'a' && ch = 'A' && ch <= 'Z' {
res += 10 + 26 + (mod - 'A')
} else if ch == '_' {
res += 10 + 26 + 26
} else if ch == '-' {
res += 10 + 26 + 26 + 1
} else {
return res, fmt.Errorf("Invalid logKey character: '%c'", res)
}
}
return res, nil
}Solution
Your solution as given has a few problems. Firstly,
I'd suggest a solution like this:
That way you can easily change the character set you're working with, and the code becomes a lot more readable. It could be made more flexible by using
You still need to include checks for non-Latin1 UTF-8 characters such as
In terms of testing for correctness, you should write unit tests (preferably table driven) to be sure that your code is working correctly. Dave Cheney has a good post on Writing table driven tests in Go that you should read.
Play for my solution
DecodeLogKey doesn't work, as you're ranging over the index of logKey rather than the value of logKey. Also, the range will start from the first character in the string, and for what you're doing, you need it to start from the last character in the string.I'd suggest a solution like this:
var codes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-"
func EncodeLogKey(id int64) string {
str := make([]byte, 0, 12)
if id == 0 {
return "0"
}
for id > 0 {
ch := codes[id%64]
str = append(str, byte(ch))
id /= 64
}
return string(str)
}
func DecodeLogKey(logKey string) (int64, error) {
res := int64(0)
for i := len(logKey); i > 0; i-- {
ch := logKey[i-1]
res *= 64
mod := strings.IndexRune(codes, rune(ch))
if mod == -1 {
return -1, fmt.Errorf("Invalid logKey character: '%c'", ch)
}
res += int64(mod)
}
return res, nil
}That way you can easily change the character set you're working with, and the code becomes a lot more readable. It could be made more flexible by using
len(codes) as the base rather than assuming it's 64.You still need to include checks for non-Latin1 UTF-8 characters such as
好 if you want to be really thorough.In terms of testing for correctness, you should write unit tests (preferably table driven) to be sure that your code is working correctly. Dave Cheney has a good post on Writing table driven tests in Go that you should read.
Play for my solution
Code Snippets
var codes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-"
func EncodeLogKey(id int64) string {
str := make([]byte, 0, 12)
if id == 0 {
return "0"
}
for id > 0 {
ch := codes[id%64]
str = append(str, byte(ch))
id /= 64
}
return string(str)
}
func DecodeLogKey(logKey string) (int64, error) {
res := int64(0)
for i := len(logKey); i > 0; i-- {
ch := logKey[i-1]
res *= 64
mod := strings.IndexRune(codes, rune(ch))
if mod == -1 {
return -1, fmt.Errorf("Invalid logKey character: '%c'", ch)
}
res += int64(mod)
}
return res, nil
}Context
StackExchange Code Review Q#71272, answer score: 3
Revisions (0)
No revisions yet.