Skip to content

Instantly share code, notes, and snippets.

@Pagliacii
Last active October 22, 2019 19:37
Show Gist options
  • Save Pagliacii/dca0f6b732c19045d258eaee81917071 to your computer and use it in GitHub Desktop.
Save Pagliacii/dca0f6b732c19045d258eaee81917071 to your computer and use it in GitHub Desktop.
Golang version of the base62 algorithm. Details: https://gist.github.com/bhelx/778542
package main
import (
"fmt"
"log"
"math"
"os"
"regexp"
"strconv"
"github.com/urfave/cli"
)
const (
BASE = 62
DIGIT_OFFSET = 48
LOWERCASE_OFFSET = 61
UPPERCASE_OFFSET = 55
)
func reverse(s string) string {
runes := []rune(s)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return string(runes)
}
func char2ord(char string) (int, error) {
if matched, _ := regexp.MatchString("[0-9]", char); matched {
return int([]rune(char)[0] - DIGIT_OFFSET), nil
} else if matched, _ := regexp.MatchString("[A-Z]", char); matched {
return int([]rune(char)[0] - UPPERCASE_OFFSET), nil
} else if matched, _ := regexp.MatchString("[a-z]", char); matched {
return int([]rune(char)[0] - LOWERCASE_OFFSET), nil
} else {
return -1, fmt.Errorf("%s is not a valid character", char)
}
}
func ord2char(ord int) (string, error) {
switch {
case ord < 10:
return string(ord + DIGIT_OFFSET), nil
case ord >= 10 && ord <= 35:
return string(ord + UPPERCASE_OFFSET), nil
case ord >= 36 && ord < 62:
return string(ord + LOWERCASE_OFFSET), nil
default:
return "", fmt.Errorf("%d is not a valid integer in the range of base %d", ord, BASE)
}
}
func Decode(str string) (int, error) {
sum := 0
for i, c := range reverse(str) {
if d, err := char2ord(string(c)); err == nil {
sum = sum + d*int(math.Pow(BASE, float64(i)))
} else {
return -1, err
}
}
return sum, nil
}
func Encode(digits int) (string, error) {
if digits == 0 {
return "0", nil
}
str := ""
for digits >= 0 {
remainder := digits % BASE
if s, err := ord2char(remainder); err != nil {
return "", err
} else {
str = s + str
}
if digits == 0 {
break
}
digits = int(digits / BASE)
}
return str, nil
}
func main() {
var decode bool
app := cli.NewApp()
app.Name = "Base62Convertor"
app.Usage = "Encode digits to short strings or decode short strings to digits"
app.Flags = []cli.Flag{
cli.BoolFlag{
Name: "decode, d",
Usage: "Use decode function",
Destination: &decode,
},
}
app.Action = func(c *cli.Context) error {
for _, arg := range c.Args() {
if decode {
if d, err := Decode(arg); err != nil {
return err
} else {
fmt.Printf("Decode: %s => %d\n", arg, d)
}
} else {
d, err := strconv.Atoi(arg)
if err != nil {
return err
}
if s, err := Encode(d); err != nil {
return err
} else {
fmt.Printf("Encode: %s => %s\n", arg, s)
}
}
}
return nil
}
err := app.Run(os.Args)
if err != nil {
log.Fatal(err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment