-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
/
isisogram.go
71 lines (56 loc) · 1.45 KB
/
isisogram.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
// Checks if a given string is an isogram.
// A first-order isogram is a word in which no letter of the alphabet occurs more than once.
// A second-order isogram is a word in which each letter appears twice.
// A third-order isogram is a word in which each letter appears three times.
// wiki: https://en.wikipedia.org/wiki/Heterogram_(literature)#Isograms
// Author: M3talM0nk3y
package strings
import (
"errors"
"regexp"
"strings"
)
type IsogramOrder int
const (
First IsogramOrder = iota + 1
Second
Third
)
func hasDigit(text string) bool {
re := regexp.MustCompile(`\d`)
return re.MatchString(text)
}
func hasSymbol(text string) bool {
re := regexp.MustCompile(`[-!@#$%^&*()+]`)
return re.MatchString(text)
}
func IsIsogram(text string, order IsogramOrder) (bool, error) {
if order < First || order > Third {
return false, errors.New("Invalid isogram order provided")
}
text = strings.ToLower(text)
text = strings.Join(strings.Fields(text), "")
if hasDigit(text) || hasSymbol(text) {
return false, errors.New("Cannot contain numbers or symbols")
}
letters := make(map[string]int)
for _, c := range text {
l := string(c)
if _, ok := letters[l]; ok {
letters[l] += 1
if letters[l] > 3 {
return false, nil
}
continue
}
letters[l] = 1
}
mapVals := make(map[int]bool)
for _, v := range letters {
mapVals[v] = true
}
if _, ok := mapVals[int(order)]; ok && len(mapVals) == 1 {
return true, nil
}
return false, nil
}