114 lines
2.0 KiB
Go
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
|
|
}
|