package profanity import ( "bufio" "os" "profanity/common" "profanity/common/decanter" "strings" ) type Filter struct { words map[string]string Decanter decanter.Decanter transforms []common.TransformFunc } func New() *Filter { dec := decanter.NewDefaultDecanter() return &Filter{ words: make(map[string]string, 3000), Decanter: dec, transforms: []common.TransformFunc{dec.DecantTransform}, } } //FilterWord //curse is "" if bad == false, else curse is populated with the match func (F *Filter) FilterWord(s string) (bad bool, curse string, form string) { forms := common.FlattenTransformFunc(F.transforms)(s) for _, form := range forms { if curse, ok := F.words[form]; ok { return true, curse, form } for _, v := range F.words { if strings.Contains(form, v) { return true, curse, form } } } return false, "", "" } func (F *Filter) CensorSentence(s string, replacer string) (censored string) { return F.CensorSentenceN(s, replacer, 0) } func (F *Filter) CensorSentenceMany(s string, replacer string, widths ...uint8) (censored string) { sentence := s for _, width := range widths { sentence = F.CensorSentenceN(sentence, replacer, width) } return sentence } func (F *Filter) CensorSentenceToN(s string, replacer string, maxwidth uint8) (censored string) { sentence := s for width := uint8(0); width < maxwidth; width++ { sentence = F.CensorSentenceN(sentence, replacer, width) } return sentence } func (F *Filter) CensorSentenceN(s string, replacer string, width uint8) (censored string) { sep := " " sb := new(strings.Builder) words := strings.Split(s, sep) for idx := 0; idx < len(words); idx++ { original := words[idx] word := words[idx] for i := 1; i <= int(width); i++ { if len(words) > (idx + i) { word = word + " " + words[idx+i] } } if bad, _, form := F.FilterWord(word); bad { idx = idx + int(width) sb.WriteString(strings.Repeat(replacer, len(form))) } else { sb.WriteString(original) } sb.WriteString(sep) } return strings.TrimSpace(sb.String()) } func (F *Filter) MustAddFile(file *os.File, err error) { if err != nil { panic(err) } F.AddFile(file) } func (F *Filter) AddFile(file *os.File) { scanner := bufio.NewScanner(file) for scanner.Scan() { txt := scanner.Text() F.AddWord(txt) } } func (F *Filter) AddWords(wx []string) { for _, w := range wx { F.AddWord(w) } } func (F *Filter) AddWord(w string) { F.words[w] = w }