Generate 6-digit Verification Code with Golang? - go

Generate 6-digit code for phone verification,
The following is a very simple approach that I have used
package main
import (
"fmt"
"math/rand"
"time"
)
var randowCodes = [...]byte{
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
}
func main() {
var r *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < 3; i++ {
var pwd []byte = make([]byte, 6)
for j := 0; j < 6; j++ {
index := r.Int() % len(randowCodes)
pwd[j] = randowCodes[index]
}
fmt.Printf("%s\n", string(pwd))
}
}
Do you have a better way to do this?

You may use "crypto/rand" package: which implements a cryptographically secure pseudorandom number generator. (try on The Go Playground):
package main
import (
"crypto/rand"
"fmt"
"io"
)
func main() {
for i := 0; i < 3; i++ {
fmt.Println(EncodeToString(6))
}
}
func EncodeToString(max int) string {
b := make([]byte, max)
n, err := io.ReadAtLeast(rand.Reader, b, max)
if n != max {
panic(err)
}
for i := 0; i < len(b); i++ {
b[i] = table[int(b[i])%len(table)]
}
return string(b)
}
var table = [...]byte{'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'}
output:
640166
195174
221966
And see: How to generate a random string of a fixed length in golang?

I've forked user6169399's answer, using crypto/rand with const string and small modifications, this is the result:
import (
"crypto/rand"
)
const otpChars = "1234567890"
func GenerateOTP(length int) (string, error) {
buffer := make([]byte, length)
_, err := rand.Read(buffer)
if err != nil {
return "", err
}
otpCharsLength := len(otpChars)
for i := 0; i < length; i++ {
buffer[i] = otpChars[int(buffer[i])%otpCharsLength]
}
return string(buffer), nil
}

I think it is the easiest way:
// generate new recovery code
t := fmt.Sprint(time.Now().Nanosecond())
fmt.Println(t[:6])
output:
524339
743142
243470
function use:
func GenerateCode() string {
return fmt.Sprint(time.Now().Nanosecond())[:6]
}
output:
302663
477258
678557

You can use rand.Int() from crypto/rand to also generate randomness
import (
"crypto/rand"
)
func GenerateOTPCode(length int) (string, error) {
seed := "012345679"
byteSlice := make([]byte, length)
for i := 0; i < length; i++ {
max := big.NewInt(int64(len(seed)))
num, err := rand.Int(rand.Reader, max)
if err != nil {
return "", err
}
byteSlice[i] = seed[num.Int64()]
}
return string(byteSlice), nil
}

make use of math/rand:
func genCaptchaCode() string {
r := rand.New(rand.NewSource(time.Now().UnixNano()))
var codes [6]byte
for i := 0; i < 6; i++ {
codes[i] = uint8(48 + r.Intn(10))
}
return string(codes[:])
}
make use of crypto/rand (more security):
func genCaptchaCode() (string, error) {
codes := make([]byte, 6)
if _, err := rand.Read(codes); err != nil {
return "", err
}
for i := 0; i < 6; i++ {
codes[i] = uint8(48 + (codes[i] % 10))
}
return string(codes), nil
}

I needed a bit simpler and flat solution so I came up with this
// Since Go 1.20 rand.Seed() deprecated
rand.New(rand.NewSource(time.Now().UnixNano()))
// generates a random number in the range of [0, 900000)
// We add 100000 to the result to ensure the minimum value is 100000
r := rand.Intn(900000) + 100000
fmt.Println(r)
a side note: rand.Intn(900000) never generates 900000 the max number is 899999 so the code never generates 1,000,000

To account for the observation given by #Tom Anderson, a more appropriate answer using real uniform distribution and a simpler code would be:
func GenerateOTP(maxDigits uint32) string {
bi, err := rand.Int(
rand.Reader,
big.NewInt(int64(math.Pow(10, float64(maxDigits)))),
)
if err != nil {
panic(err)
}
return fmt.Sprintf("%0*d", maxDigits, bi)
}
go playground

Related

Generate random values for golange

I need a random password generator for a project, I need to make 10 of them. I found this function (random), but when I run it in a loop, it generates the same passwords. I don't know what's the problem.
func main() {
for i := 0; i < 10; i++ {
a := random()
fmt.Println(a)
}
}
func random() string {
rand.Seed(time.Now().UnixNano())
chars := []rune("abcdefghijklmnopqrstuvwxyz" + "0123456789")
length := 10
var b strings.Builder
for i := 0; i < length; i++ {
b.WriteRune(chars[rand.Intn(len(chars))])
}
str := b.String()
return str
}
Adapting your example code and refactoring it a bit:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rp := newRandPass(rand.New(rand.NewSource(time.Now().UnixNano())), 10, 10)
fmt.Println(rp.passwords())
}
type RandPass struct {
r *rand.Rand
num int
len int
}
func newRandPass(r *rand.Rand, num, len int) *RandPass {
return &RandPass{r, num, len}
}
func (r *RandPass) passwords() []string {
chars := []rune("abcdefghijklmnopqrstuvwxyz" + "0123456789")
passwords := make([]string, r.num)
for i := 0; i < r.num; i++ {
s := make([]rune, r.len)
for j := 0; j < r.len; j++ {
s[j] = chars[r.r.Intn(len(chars))]
}
passwords[i] = string(s)
}
return passwords
}
$ go run .
[rt97kzwjwe 5ziim05exh 40dfly93et v5tga5bwv9 avf2p2dpjx hsz4lca0jv 8r7bvvtu5l 9byf3mjq6r sdr2mpo54g cjx4mq6c0t]

computing complexity of an anagram finder implementation

Given below code
package main
import (
"fmt"
"sort"
"strings"
)
func main() {
s := []string{"eat", "tea", "tan", "ate", "nat", "bat"}
result := groupAnagrams(s)
fmt.Println(result)
}
func groupAnagrams(s []string) (out [][]string) {
tmp := map[string][]string{}
for _, v := range s {
x := strings.Split(v, "")
sort.Strings(x)
anagram := strings.Join(x, "")
items, ok := tmp[anagram]
if ok {
items = append(items, v)
tmp[anagram] = items
continue
}
tmp[anagram] = []string{v}
}
var keys []string
for key := range tmp {
keys = append(keys, key)
}
sort.Strings(keys)
for _, key := range keys {
sort.Strings(tmp[key])
out = append(out, tmp[key])
}
return
}
And its tests here https://play.golang.org/p/k8F1-FAC_au
can you help figuring the complexity ?
In my understanding, and without checking thoroughly the documentation.
for _, v := range s { // o(n)
sort.Strings(keys) //o(log n)
x := strings.Split(v, "") / anagram := strings.Join(x, "") //o(n)
Are those correct ? Am i missing some ? How to compute the total ?
Do you account for total allocations when computing the complexity of a code ?
(not an answer, more like a formatted comment)
You get to choose what counts as "1 operation".
For example : in your for _, v := range s { ... } loop, I wouldn't count the processing of one single v value :
x := strings.Split(v, "")
sort.Strings(x)
anagram := strings.Join(x, "")
items, ok := tmp[anagram]
if ok {
items = append(items, v)
tmp[anagram] = items
continue
}
tmp[anagram] = []string{v}
as "1 operation". More like something that depends on len(v).
So the length of the items in your starting set will probably appear in your end formula.
this is not an answer, but, little insight as to anyone else having to deal with such things. may that help you.
I slightly revised stuff here and their, then gave a shot to a Godel-inspired scheme as described at https://stackoverflow.com/a/396077/11892070
-- main.go --
package main
import (
"fmt"
"sort"
"strings"
)
func main() {
input := []string{"tan", "nat", "⌘", "日本語", "語日本"}
freq := map[rune]int{}
for _, word := range input {
x, err := hashWord(word, freq)
fmt.Println(word, "=>", x, "err=", err)
}
}
func groupAnagramsUsingSort(s []string, tmp map[string][]string, out [][]string) [][]string {
for k := range tmp {
delete(tmp, k)
}
for i := 0; i < len(out); i++ {
out[i] = out[i][:0]
}
out = out[:0]
for _, v := range s {
x := strings.Split(v, "")
sort.Strings(x)
anagram := strings.Join(x, "")
items, ok := tmp[anagram]
if ok {
items = append(items, v)
tmp[anagram] = items
continue
}
tmp[anagram] = []string{v}
}
for key := range tmp {
out = append(out, tmp[key])
}
return out
}
func groupAnagramsUsingHash(s []string, tmp map[int][]string, out [][]string) [][]string {
for k := range tmp {
delete(tmp, k)
}
for i := 0; i < len(out); i++ {
out[i] = out[i][:0]
}
out = out[:0]
freq := map[rune]int{}
for _, v := range s {
hash, _ := hashWord(v, freq)
items, ok := tmp[hash]
if ok {
items = append(items, v)
tmp[hash] = items
continue
}
tmp[hash] = []string{v}
}
for key := range tmp {
out = append(out, tmp[key])
}
return out
}
var primes = []int{2, 41, 37, 47, 3, 67, 71, 23, 5, 101, 61, 17, 19, 13, 31, 43, 97, 29, 11, 7, 73, 83, 79, 89, 59, 53}
var ErrNonASCII = fmt.Errorf("non ascii letter detected")
func getFrequencyMap(word string, freq map[rune]int) (map[rune]int, error) {
for k := range freq {
delete(freq, k)
}
for _, r := range word {
if r-97 < 0 || int(r-97) > len(primes) {
return nil, ErrNonASCII
}
x := freq[r]
freq[r] = x + 1
}
return freq, nil
}
func hashWord(word string, freq map[rune]int) (int, error) {
var err error
freq, err = getFrequencyMap(word, freq)
if err != nil {
return -1, err
}
product := 1
for letter, r := range freq {
product = product * primes[letter-97]
for e := 1; e < r; e++ {
product = product * product
}
}
return product, nil
}
-- main_test.go --
package main
import (
"reflect"
"sort"
"testing"
)
type expectation struct {
input []string
want [][]string
}
var expectations = []expectation{
expectation{
input: []string{"eat", "tea", "tan", "ate", "nat", "bat"},
want: [][]string{
[]string{"ate", "eat", "tea"},
[]string{"bat"},
[]string{"nat", "tan"},
},
},
expectation{
input: []string{"eaft", "tea", "taen", "ate", "nate", "batf"},
want: [][]string{
[]string{"batf"},
[]string{"eaft"},
[]string{"tea", "ate"},
[]string{"taen", "nate"},
},
},
expectation{
input: []string{""},
want: [][]string{
[]string{""},
},
},
expectation{
input: []string{"a"},
want: [][]string{
[]string{"a"},
},
},
}
func TestUsingSort(t *testing.T) {
tmp := map[string][]string{}
out := [][]string{}
for _, expectation := range expectations {
out = groupAnagramsUsingSort(expectation.input, tmp, out)
if len(out) != len(expectation.want) {
t.Fatalf("unexpected output,\nwanted=%#v\ngot =%#v\n", expectation.want, out)
}
for i := 0; i < len(out); i++ {
sort.Strings(out[i])
sort.Strings(expectation.want[i])
}
sort.Slice(out, func(i int, j int) bool {
return len(out[i]) < len(out[j])
})
sort.Slice(expectation.want, func(i int, j int) bool {
return len(expectation.want[i]) < len(expectation.want[j])
})
sort.Slice(out, func(i int, j int) bool {
return (len(out[i]) > 0 &&
len(out[j]) > 0 &&
out[i][0] < out[j][0])
})
sort.Slice(expectation.want, func(i int, j int) bool {
return (len(expectation.want[i]) > 0 &&
len(expectation.want[j]) > 0 &&
expectation.want[i][0] < expectation.want[j][0])
})
for i := 0; i < len(out); i++ {
if !reflect.DeepEqual(out[i], expectation.want[i]) {
t.Fatalf("unexpected output,\nwanted=%#v\ngot =%#v\n", expectation.want, out)
}
}
}
}
func TestUsingHash(t *testing.T) {
tmp := map[int][]string{}
out := [][]string{}
for _, expectation := range expectations {
out = groupAnagramsUsingHash(expectation.input, tmp, out)
if len(out) != len(expectation.want) {
t.Fatalf("unexpected output,\nwanted=%#v\ngot =%#v\n", expectation.want, out)
}
for i := 0; i < len(out); i++ {
sort.Strings(out[i])
sort.Strings(expectation.want[i])
}
sort.Slice(out, func(i int, j int) bool {
return len(out[i]) < len(out[j])
})
sort.Slice(expectation.want, func(i int, j int) bool {
return len(expectation.want[i]) < len(expectation.want[j])
})
sort.Slice(out, func(i int, j int) bool {
return (len(out[i]) > 0 &&
len(out[j]) > 0 &&
out[i][0] < out[j][0])
})
sort.Slice(expectation.want, func(i int, j int) bool {
return (len(expectation.want[i]) > 0 &&
len(expectation.want[j]) > 0 &&
expectation.want[i][0] < expectation.want[j][0])
})
for i := 0; i < len(out); i++ {
if !reflect.DeepEqual(out[i], expectation.want[i]) {
t.Fatalf("unexpected output,\nwanted=%#v\ngot =%#v\n", expectation.want, out)
}
}
}
}
func BenchmarkUsingSort(b *testing.B) {
tmp := map[string][]string{}
out := [][]string{}
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
for _, expectation := range expectations {
out = groupAnagramsUsingSort(expectation.input, tmp, out)
_ = out
}
}
}
func BenchmarkUsingHash(b *testing.B) {
tmp := map[int][]string{}
out := [][]string{}
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
for _, expectation := range expectations {
out = groupAnagramsUsingHash(expectation.input, tmp, out)
_ = out
}
}
}
Benchmark result
$ go test -bench=. -v .
=== RUN TestUsingSort
--- PASS: TestUsingSort (0.00s)
=== RUN TestUsingHash
--- PASS: TestUsingHash (0.00s)
goos: linux
goarch: amd64
BenchmarkUsingSort
BenchmarkUsingSort-4 344438 3315 ns/op 787 B/op 29 allocs/op
BenchmarkUsingHash
BenchmarkUsingHash-4 410810 2911 ns/op 496 B/op 17 allocs/op
PASS
ok _/home/clementauger/tmp 2.408s

How to convert an int64 to int in Go?

In Go, what is the best strategy for converting int64 to int? I am having difficulty comparing the two
package main
import (
"math"
"strings"
"strconv"
)
type largestPrimeFactor struct {
N int
Result int
}
func main() {
base := largestPrimeFactor{N:13195}
max := math.Sqrt(float64(base.N))
maxStr := strconv.FormatFloat(max, 'E', 'G', 64)
maxShift := strings.Split(maxStr, ".")[0]
maxInt, err := strconv.ParseInt(maxShift, 10, 64)
if (err != nil) {
panic(err)
}
on this next line
for a := 2; a < maxInt; a++ {
if isPrime(a) {
if base.N % a == 0 {
base.Result = a
}
}
}
println(base)
}
func isPrime(n int) bool {
flag := false
max := math.Sqrt(float64(n))
maxStr := strconv.FormatFloat(max, 'E', 'G', 64)
maxShift := strings.Split(maxStr, ".")[0]
maxInt, err := strconv.ParseInt(maxShift, 10, 64)
if (err != nil) {
panic(err)
}
for a := 2; a < maxInt; a++ {
if (n % a == 0) {
flag := true
}
}
return flag
}
You convert them with a type "conversion"
var a int
var b int64
int64(a) < b
When comparing values, you always want to convert the smaller type to the larger. Converting the other way will possibly truncate the value:
var x int32 = 0
var y int64 = math.MaxInt32 + 1 // y == 2147483648
if x < int32(y) {
// this evaluates to false, because int32(y) is -2147483648
Or in your case to convert the maxInt int64 value to an int, you could use
for a := 2; a < int(maxInt); a++ {
which would fail to execute correctly if maxInt overflows the max value of the int type on your system.
I came here because of the title, "How to convert an int64 to int in Go?". The answer is,
int(int64Var)
It is correct to use the strconv package
strconv.FormatInt(int64Var, 10)

Parse number string digits

I am trying to calculate the multiplication result of a few digits which are part of a long digits string. Here is my code:
package main
import (
"fmt"
"strconv"
)
func main() {
inputNum := "73167176531330624919225119"
mult := getMult(3, inputNum)
fmt.Printf("Mult = %d", mult)
}
func getMult(startIndex int, inputNum string) int {
mult := 0
for i := 0; i < 10; i++ {
digit, err := strconv.Atoi(string(inputNum[startIndex+i]))
if err != nil {
mult *= int(digit)
} else {
fmt.Printf("Error converting %s to int : %s\n", string(inputNum[startIndex+i]), err.Error())
}
}
return mult
}
The result I want to get is 6*7*1*7*6*5*3*1*3*3 = 238140
But I an getting a runtime error:
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x20 pc=0x40130e]
goroutine 1 [running]:
main.getMult(0x3, 0x534d40, 0x1a, 0x4d2701)
test.go:25 +0x17e
main.main()
test.go:10 +0x55
exit status 2
There are a couple problems...
First, you need to start mult at 1, otherwise you will just continually multiply by 0 and always get 0.
Secondly you have the logic for your err check flipped. It should be if err == nil
This seems to do what you want:
func getMult(startIndex int, inputNum string) int {
mult := 1
for i := 0; i < 10; i++ {
digit, err := strconv.Atoi(string(inputNum[startIndex+i]))
if err == nil {
mult *= int(digit)
} else {
fmt.Println(err)
}
}
return mult
}
The error you were getting was because you were trying to print err.Error() when err itself was nil (due to the logical flip of != and ==)
your code will work with fixing these two typos:
change mult := 0 to mult := 1
and change err != nil to err == nil like this:
package main
import (
"fmt"
"strconv"
)
func main() {
inputNum := "73167176531330624919225119"
mult := getMult(3, inputNum)
fmt.Printf("Mult = %d", mult)
}
func getMult(startIndex int, inputNum string) int {
mult := 1
for i := 0; i < 10; i++ {
digit, err := strconv.Atoi(string(inputNum[startIndex+i]))
if err == nil {
mult *= int(digit)
} else {
fmt.Printf("Error converting %s to int : %s\n", string(inputNum[startIndex+i]), err.Error())
}
}
return mult
}
also you may use inputNum[3:13] to get new string from index 3 with length 10,
and you may use int(v - '0') to convert one character to integer number,
then use for range like this:
package main
import "fmt"
func main() {
inputNum := "73167176531330624919225119"
mult := getMult(inputNum[3:13])
fmt.Printf("Mult = %d \n", mult) // Mult = 238140
}
func getMult(str string) int {
m := 1
for _, v := range str {
if v >= '0' && v <= '9' {
m *= int(v - '0')
} else {
fmt.Printf("Error converting %q to int\n", v)
break
}
}
return m
}
output:
Mult = 238140

Iterate over two strings at the same time

I am just wondering if there is any beautiful way to iterate over two strings at the same time:
var ascii_runes = []rune(string_1)
var shifted_runes = []rune(string_2)
for i := 0; i < len(string_1); i++ {
fmt.Println(string(ascii_runes[i]) + string(shifted_runes[i]))
}
Not sure IIUC, but for example:
package main
import (
"fmt"
)
var (
ascii = []rune("string1")
shifted = []rune("STRING!")
)
func main() {
for i, v := range ascii {
fmt.Printf("%c%c\n", v, shifted[i])
}
}
Also here: http://play.golang.org/p/2ruvLFg_qe
Output:
sS
tT
rR
iI
nN
gG
1!
For example,
package main
import "fmt"
func main() {
var runes_1, runes_2 = []rune("string_1"), []rune("string_2")
for i := 0; i < len(runes_1) && i < len(runes_2); i++ {
fmt.Println(string(runes_1[i]) + string(runes_2[i]))
}
}
Output:
ss
tt
rr
ii
nn
gg
__
12
Not particularly beautiful, but an efficient way is to use strings.NewReader and its ReadRune method.
func Less(s1, s2 string) bool {
rdr1 := strings.NewReader(s1)
rdr2 := strings.NewReader(s2)
for {
rune1, _, err1 := rdr1.ReadRune()
rune2, _, err2 := rdr2.ReadRune()
if err2 == io.EOF { return false }
if err1 == io.EOF { return true }
if rune1 != rune2 { return rune1 < rune2 }
}
}

Resources