package interactors import ( "regexp" "sort" "strings" ) type simpleSet map[string]bool var unicode = regexp.MustCompile("[^\x00-\x7F]+") func (s simpleSet) Contains(other string) bool { enabled, exists := s[other] return exists && enabled } // Returns the different of two slices of strings; effectively a set arithmetic operation on two slices of strings func DistinctValues(slice1, slice2 []string) []string { sets := []simpleSet{ sliceToSimpleSet(slice1), sliceToSimpleSet(slice2), } discardKeysFromOther(sets[0], sets[1]) discardKeysFromOther(sets[1], sets[0]) var exclusiveValues []string for _, k := range allKeys(sets...) { for _, set := range sets { if set[k] == true { exclusiveValues = append(exclusiveValues, k) } } } sort.Strings(exclusiveValues) return exclusiveValues } func SetSubtract(add, negate []string) []string { toRemove := sliceToSimpleSet(negate) var result []string for _, a := range add { if !toRemove.Contains(a) { result = append(result, a) } } return result } func SetUnion(slice1, slice2 []string) []string { union := allKeys( sliceToSimpleSet( append( slice1, slice2..., ), ), ) sort.Strings(union) return union } func sliceToSimpleSet(s []string) simpleSet { m := make(simpleSet, len(s)) for _, val := range s { m[val] = true } return m } func discardKeysFromOther(s1, s2 simpleSet) { for k := range s1 { if _, exists := s2[k]; exists { s2[k] = false } } } func allKeys(sets ...simpleSet) []string { totalCount := 0 for _, s := range sets { totalCount += len(s) } keys := make([]string, totalCount) index := 0 for _, s := range sets { for k := range s { keys[index] = k index++ } } return keys } func FilterNoUnicode(s string) string { badCharacters := sliceToSimpleSet( unicode.FindAllString(s, -1), ) if len(badCharacters) == 0 { return s } validCharacters := make([]string, 0, len(s)) for _, rune_ := range s { char := string(rune_) if !badCharacters.Contains(char) { validCharacters = append(validCharacters, char) } } return strings.Join( validCharacters, "", ) }