search/search.go
2018-12-20 00:20:11 +01:00

114 lines
2.0 KiB
Go

package search
import (
"sort"
"strings"
)
var ignoreWords = []string{`a`, `of`, `in`, `the`, `wa`, `ga`, `no`, `ni`, `wo`, `he`, `o`, `ka`}
var replaceCharacters = strings.Split(`〜☆♪・〈〉「」!『』²Ⅱ+[](),.!?\/{}+-_=~"'@#$%^&*|;:<>`, ``)
// ID ...
type ID struct {
ID int
Score float64
Title []string
}
// Search ...
type Search struct {
Titles map[interface{}][][]string
IgnoreWords []string
RemoveCharacters []string
}
// CleanSearch ...
func CleanSearch(title string) []string {
s := []string{}
for _, c := range replaceCharacters {
title = strings.Replace(title, c, ` `, -1)
}
for _, v := range strings.Split(title, ` `) {
matched := false
if v == `` || v == ` ` {
continue
}
for _, w := range ignoreWords {
if v == w {
matched = true
}
}
if !matched {
s = append(s, strings.ToLower(v))
}
}
return s
}
// IndexSearch ...
func (DB *Search) IndexSearch(id interface{}, st [][]string) {
if DB.Titles == nil {
DB.Titles = make(map[interface{}][][]string)
}
for _, t := range st {
DB.Titles[id] = append(DB.Titles[id], t)
}
}
// Match ...
func (DB *Search) Match(Title string) []interface{} {
IDS := []ID{}
title := CleanSearch(strings.ToLower(Title))
mainLoop:
for i := range DB.Titles {
for _, t := range DB.Titles[i] {
if len(t) == 0 {
continue
}
sim := similarity(t, title)
if sim > 0 {
IDS = append(IDS, ID{ID: i.(int), Score: sim, Title: t})
continue mainLoop
}
}
}
sort.Slice(IDS, func(i, j int) bool {
return IDS[i].Score > IDS[j].Score
})
ids := []interface{}{}
for _, v := range IDS {
ids = append(ids, v.ID)
}
return ids
}
func similarity(a, b []string) float64 {
var s float64
var matched []int
loop:
for _, i := range a {
for f, l := range b {
if i == l && !intInSlice(f, matched) {
s++
matched = append(matched, f)
continue loop
} else {
s = s - 0.125
}
}
}
return s
}
func intInSlice(a int, list []int) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}